@ivorysi
2018-01-05T00:27:19.000000Z
字数 19877
阅读 1407
笔记
对于互质的两个数a,b,f(ab)=f(a)*f(b)
对于任意两个数,f(ab)=f(a)f(b)
欧拉函数表示[1,n]中与n互质的数,
欧拉函数是积性函数,但不是完全积性函数
有一些特殊的小性质
[1,n]中与n互质的数的和是
因为互质的数总是成对出现,例如k和n互质,n-k必然也和n互质,否则k不与n互质
如果n有平方数因子的话
如果n有k个质因子的话
如果n=1的话
表示n的所有正因子k次幂之和
表示n的所有正因子之和
其余时候全是0
这个式子可以用容斥来考虑
1的时候式子是n,然后对于的一个质因子,我们筛去所有个,也就是p的倍数,但是会重复筛掉一些数,如果有那么这个d就被删掉了两次,我们就加回来,如果有它被减去了3次,又被恢复了3次,然后再减去它……所以就得到了这个式子
设n中有k个不同的质因子
考虑杨辉三角,组合数之间分别填上+号和-号,最后的和一定是0
只有当n=1的时候,这个式子的值才是1
若有两个函数f,g
则他们也满足
它还有另一种形式
若两个函数满足
则
给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7
输入仅一行,包含两个整数n, k。
输出仅一行,即j(n, k)。
5 3
7
50%的数据满足:1<=n, k<=1000 100%的数据满足:1<=n ,k<=10^9
可以拆式子
而取值只有个
因为如果,那么有种不同取值,时,取值只能在以内,那么值只有
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
//#define ivorysi
using namespace std;
typedef long long ll;
int n,k;
ll ans;
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
scanf("%d%d",&n,&k);
if(n>k) {
ans=(ll)(n-k)*k;
n=k;
}
int t,r;
for(int i=1;i<=n;i=r+1) {
t=k/i;r=k/t;
if(r>n) r=n;
ans+=(ll)(r-i+1)*k-(ll)(r-i+1)*(i+r)/2*t;
}
printf("%lld\n",ans);
return 0;
}
Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。现在问题来了:给定一个整数N,你需要求出∑gcd(i, N)(1<=i <=N)。
一个整数,为N。
一个整数,为所求的答案。
6
15
【数据范围】
对于60%的数据,0 对于100%的数据,0
如何快速求出这个
我们枚举每个质因子有几个就好了,可以dfs
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long ll;
ll n;
ll ans;
ll prime[MAXN];
int cnt[MAXN],tot;
void dfs(int dep,ll now,ll eu) {
if(dep>tot) {
ans+=(n/now)*eu;
return;
}
dfs(dep+1,now,eu);
ll t=1;
siji(i,1,cnt[dep]) {
t=t*prime[dep];
dfs(dep+1,now*t,eu*t/prime[dep]*(prime[dep]-1));
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
scanf("%lld",&n);
int t=n;
for(int i=2;i<=t/i;++i) {
if(t%i==0) {
prime[++tot]=i;
while(t%i==0) {
++cnt[tot];
t/=i;
}
}
}
if(t!=1) {
prime[++tot]=t;
cnt[tot]=1;
}
dfs(1,1,1);
printf("%lld\n",ans);
return 0;
}
Given n, calculate the sum LCM(1,n) + LCM(2,n) + .. + LCM(n,n), where LCM(i,n) denotes the Least Common Multiple of the integers i and n.
The first line contains T the number of test cases. Each of the next T lines contain an integer n.
Output T lines, one for each test case, containing the required sum.
3
1
2
5
1
4
55
Constraints
1 <= T <= 300000
1 <= n <= 1000000
除法比乘法慢了那么多!!!
这道题卡常!!!
我们预处理每个数的与它互质且比它小的数的和,然后对于每个n枚举约数
拼命卡常啊QAQ
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long ll;
ll phi[MAXN*2];
bool nonprime[MAXN*2];
int prime[MAXN*2],tot;
int T,n;
ll ans;
int read() {
char c=getchar();
int res=0;
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') {
res=res*10+c-'0';
c=getchar();
}
return res;
}
void out(ll x) {
if(x>=10) {
out(x/10);
}
putchar('0'+x%10);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
phi[1]=1;
siji(i,2,1000000) {
if(!nonprime[i]) {
phi[i]=i-1;
prime[++tot]=i;
}
siji(j,1,tot) {
if((ll)prime[j]*i>1000000) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) {
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
siji(i,2,1000000) phi[i]=phi[i]*i/2;
T=read();
while(T--) {
n=read();
ans=0;
for(int i=1;i*i<=n;++i) {
if(n%i==0) {
ans+=phi[i];
if(i*i<n) {ans+=phi[n/i];}
}
}
ans=ans*n;
out(ans);
putchar('\n');
}
return 0;
}
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a
,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个
正整数,分别为a,b,d。(1<=d<=a,b<=50000)
对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。
2
4 5 2
6 4 3
3
2
//对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(
6,3),(3,3)。
我们转化一下
求之间有多少个互质的数
以下还用表示区间左右端点
然后列出式子
然后因为只有种取值,且每段都对应一段连续的取值,然后这个东西的取值不超过
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long ll;
const int N = 50000;
int miu[N+10],prime[N+10],tot,sum[N+10],T;
bool nonprime[N+10];
ll ans=0;
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
miu[1]=1;
siji(i,2,N) {
if(!nonprime[i]) {
prime[++tot]=i;
miu[i]=-1;
}
siji(j,1,tot) {
if(i*prime[j]>N) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) break;
miu[i*prime[j]]=-miu[i];
}
}
siji(i,1,N) {
sum[i]=sum[i-1]+miu[i];
}
scanf("%d",&T);
int a,b,d;
while(T--) {
scanf("%d%d%d",&a,&b,&d);
a/=d;b/=d;
ans=0;
int n=min(a,b);
int r;
for(int i=1;i<=n;i=r+1) {
r=min(a/(a/i),b/(b/i));
if(r>n) r=n;
ans+=(ll)(a/i)*(b/i)*(sum[r]-sum[i-1]);
}
printf("%lld\n",ans);
}
return 0;
}
小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些
数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而
这丝毫不影响他对其他数的热爱。
这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一
个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了
小X。小X很开心地收下了。
然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?
包含多组测试数据。文件第一行有一个整数 T,表示测试
数据的组数。
第2 至第T+1 行每行有一个整数Ki,描述一组数据,含义如题目中所描述。
含T 行,分别对每组数据作出回答。第 i 行输出相应的
第Ki 个不是完全平方数的正整数倍的数。
4
1
13
100
1234567
1
19
163
2030745
对于 100%的数据有 1 ≤ Ki ≤ 10^9,T ≤ 50
这道题考虑容斥原理,和的性质
二分一个x,考虑快速之间有多少个非完全平方数的个数
这个就相当于,1的倍数,减去1个质数平方的倍数,加上2个质数平方的倍数……
发现这个东西符号刚好和的正负一样
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long ll;
const int N = 100000;
int miu[N+10],prime[N+10],tot,sum[N+10],T;
bool nonprime[N+10];
ll ans=0;
ll check(ll mid) {
ll res=0;
for(ll i=1;i*i<=mid;++i) {
if(miu[i]==0) continue;
res+=(ll)miu[i]*(mid/(i*i));
}
return res;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
miu[1]=1;
siji(i,2,N) {
if(!nonprime[i]) {
prime[++tot]=i;
miu[i]=-1;
}
siji(j,1,tot) {
if(i*prime[j]>N) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) break;
miu[i*prime[j]]=-miu[i];
}
}
scanf("%d",&T);
ll k;
while(T--) {
scanf("%lld",&k);
ll l=1,r=10000000000LL;
while(l<r) {
ll mid=(l+r)>>1;
if(check(mid)>=k) r=mid;
else l=mid+1;
}
printf("%lld\n",r);
}
return 0;
}
神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
傻×必然不会了,于是向你来请教……多组输入
第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M
T行,每行一个整数表示第i组数据的结果
2
10 10
100 100
30
2791
T = 10000
N, M <= 10000000
这道题按照之前某道1101的思路,可以很容易想到一个超时思路
枚举一个质数
然后我们可以设
我们只要能求出对于然后处理成前缀和就很妙了,就变成1101了
然后我们枚举每个质数,去更新它的倍数的话,根据调和级数,均摊是的
然后质数一共有个所以复杂度是可以暴力预处理
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 10000005
//#define ivorysi
using namespace std;
typedef long long ll;
ll sum[MAXN];
bool nonprime[MAXN];
int prime[MAXN],tot,n,m,miu[MAXN];
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
miu[1]=1;
siji(i,2,10000000) {
if(!nonprime[i]) {
prime[++tot]=i;
miu[i]=-1;
}
siji(j,1,tot) {
if(i>10000000/prime[j]) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) break;
miu[i*prime[j]]=-miu[i];
}
}
siji(i,1,tot) {
int t=prime[i];
while(t<=10000000) sum[t]+=miu[t/prime[i]],t+=prime[i];
}
siji(i,1,10000000) sum[i]+=sum[i-1];
int T;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
int t=min(n,m),r;
ll ans=0;
for(int i=1;i<=t;i=r+1) {
r=min(n/(n/i),m/(m/i));
if(r>t) r=t;
ans+=(ll)(sum[r]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans);
}
return 0;
}
栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量。在这些植物采集能量后,
栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起。 栋栋的植物种得非常整齐,一共有n列,每列
有m棵,植物的横竖间距都一样,因此对于每一棵植物,栋栋可以用一个坐标(x, y)来表示,其中x的范围是1至n,
表示是在第x列,y的范围是1至m,表示是在第x列的第y棵。 由于能量汇集机器较大,不便移动,栋栋将它放在了
一个角上,坐标正好是(0, 0)。 能量汇集机器在汇集的过程中有一定的能量损失。如果一棵植物与能量汇集机器
连接而成的线段上有k棵植物,则能量的损失为2k + 1。例如,当能量汇集机器收集坐标为(2, 4)的植物时,由于
连接线段上存在一棵植物(1, 2),会产生3的能量损失。注意,如果一棵植物与能量汇集机器连接的线段上没有植
物,则能量损失为1。现在要计算总的能量损失。 下面给出了一个能量采集的例子,其中n = 5,m = 4,一共有20
棵植物,在每棵植物上标明了能量汇集机器收集它的能量时产生的能量损失。 在这个例子中,总共产生了36的能
量损失。
仅包含一行,为两个整数n和m。
仅包含一个整数,表示总共产生的能量损失。
5 4
3 4
36
20
对于100%的数据:1 ≤ n, m ≤ 100,000。
这道题只要想起来某个公式,还是很简单的
这个公式就是
这个东西可以通过数学归纳法证明,就是证明如果n是一个质数的指数幂,然后n是两个质数的指数幂……就证出来了
然后我们可以列式子
然后我们发现最难算的是这个(废话)
这道题就愉快的出解了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long ll;
ll sum[MAXN];
bool nonprime[MAXN];
int prime[MAXN],tot,n,m,phi[MAXN];
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
phi[1]=1;
siji(i,2,100000) {
if(!nonprime[i]) {
prime[++tot]=i;
phi[i]=i-1;
}
siji(j,1,tot) {
if(i>100000/prime[j]) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) {
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
siji(i,1,100000) phi[i]+=phi[i-1];
scanf("%d%d",&n,&m);
int t=min(n,m),r;
ll ans=0;
for(int i=1;i<=t;i=r+1) {
r=min(n/(n/i),m/(m/i));
if(r>t) r=t;
ans+=(ll)(phi[r]-phi[i-1])*(n/i)*(m/i);
}
ans=ans*2;
ans-=(ll)n*m;
printf("%lld\n",ans);
return 0;
}
有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为
能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。
输入包含多组数据。
输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。
对每组数据,输出一行一个整数,表示答案模2^31的值。
2
4 4 3
10 10 5
20
148
1 < =N.m < =10^5 , 1 < =Q < =2×10^4
满足然后
我们可以这么算
设g(p)表示以p为最大公约数的对数有多少个
然后这个式子就可以改成
我们可以线性递推出
我们发现如果 那么约数和是
如果 那么约数和是
我们需要把维护成一个前缀和,就可以快速处理了
考虑到我们离线处理,把询问按a排序,把排序,然后不断加入并更新到i的倍数上,用树状数组维护前缀和
然后这个东西是的
每次询问是
总复杂度是
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long ll;
const int mod=(1<<30)-1+(1<<30);
const int N=100000;
int Q;
int g[N+5],prime[N+5],tot,miu[N+5],pos[N+5],ans[N+5],tr[N+5];
int f[N+5];
bool nonprime[N*2];
struct node {
int n,m,id,a;
bool operator < (const node &rhs) const {
return a<rhs.a;
}
}qry[N];
bool cmp(int a,int b) {
return f[a]<f[b];
}
int lowbit(int x) {return x&(-x);}
void Insert(int pos,int x) {
if(x==0) return;
while(pos<=N) {
tr[pos]+=x;
pos+=lowbit(pos);
}
}
int query(int pos) {
int res=0;
while(pos>0) {
res+=tr[pos];
pos-=lowbit(pos);
}
return res;
}
int _query(int l,int r) {
return query(r)-query(l-1);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
miu[1]=1;
f[1]=1;
siji(i,2,N) {
if(!nonprime[i]) {
prime[++tot]=i;
miu[i]=-1;
f[i]=i+1;
}
siji(j,1,tot) {
if(prime[j]>N/i) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) {
f[i*prime[j]]=((ll)(f[i]-f[i/prime[j]])*prime[j]+f[i]);
break;
}
miu[i*prime[j]]=-miu[i];
f[i*prime[j]]=f[i]*prime[j]+f[i];
}
}
siji(i,1,N) pos[i]=i;
sort(pos+1,pos+N+1,cmp);
scanf("%d",&Q);
siji(i,1,Q) {
scanf("%d%d%d",&qry[i].n,&qry[i].m,&qry[i].a);
qry[i].id=i;
}
sort(qry+1,qry+Q+1);
int now=1;
siji(i,1,Q) {
while(now<=N && f[pos[now]]<=qry[i].a) {
int t=pos[now];
while(t<=N) {
Insert(t,(f[pos[now]]&mod)*miu[t/pos[now]]);
t+=pos[now];
}
++now;
}
int t=min(qry[i].n,qry[i].m),r;
for(int j=1;j<=t;j=r+1) {
r=min(qry[i].n/(qry[i].n/j),qry[i].m/(qry[i].m/j));
if(r>t) r=t;
ans[qry[i].id]+=_query(j,r)*(qry[i].n/j)*(qry[i].m/j);
}
ans[qry[i].id]&=mod;
}
siji(i,1,Q) {
printf("%d\n",ans[i]);
}
return 0;
}
今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数。例如,LCM(6, 8) = 24。回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j)。一个4*5的表格如下: 1 2 3 4 5 2 2 6 4 10 3 6 3 12 15 4 4 12 4 20 看着这个表格,Crash想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当N和M很大时,Crash就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash只想知道表格里所有数的和mod 20101009的值。
输入的第一行包含两个正整数,分别表示N和M。
输出一个正整数,表示表格中所有数的和mod 20101009的值。
4 5
122
100%的数据满足N, M ≤ 10^7。
严谨认真的推一下式子
我们枚举约数,然后表示中互质的和
然后考虑怎么求
枚举是的,计算是的,总体是的,已经可以解决本题
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 100005
#define mod 20101009
//#define ivorysi
using namespace std;
typedef long long ll;
const int N=10000000;
bool nonprime[N+5];
int prime[N+5],tot,miu[N+5],n,m,ans;
int sum(int x,int y) {
return (1LL*x*(x+1)/2%mod*(1LL*y*(y+1)/2%mod))%mod;
}
int calc(int x,int y) {
int t=min(x,y),r;
int res=0;
for(int i=1;i<=t;i=r+1) {
r=min(x/(x/i),y/(y/i));
if(r>t) r=t;
res+=1LL*sum(x/i,y/i)*(miu[r]-miu[i-1])%mod;
res=(res%mod+mod)%mod;
}
return res;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
miu[1]=1;
siji(i,2,N) {
if(!nonprime[i]) {
prime[++tot]=i;
miu[i]=-1;
}
siji(j,1,tot) {
if(prime[j]>N/i) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) break;
miu[i*prime[j]]=-miu[i];
}
}
siji(i,1,N) miu[i]=1LL*i*i%mod*miu[i]%mod;
siji(i,1,N) miu[i]+=miu[i-1],miu[i]%=mod;
scanf("%d%d",&n,&m);
int r,t=min(n,m);
for(int i=1;i<=t;i=r+1) {
r=min(n/(n/i),m/(m/i));
if(r>t) r=t;
ans+=calc(n/i,m/i)*(1LL*(i+r)*(r-i+1)/2%mod)%mod;
ans%=mod;
}
ans=(ans%mod+mod)%mod;
printf("%d\n",ans);
return 0;
}
()
一个正整数T表示数据组数
接下来T行 每行两个正整数 表示N、M
T行 每行一个整数 表示第i组数据的结果
1
4 5
122
T <= 10000
N, M<=10000000
我们可以优化一下上一个式子,让它可以满足多组询问
我们发现只要求出
的前缀和我们就可以在中完成一次询问
考虑到,积性函数的约数和还是积性函数
然后我们可以在线性筛的同时求出这个函数值
当的时候我们直接让这个函数值乘上即可,因为多出来的约数的贡献全是0,所以直接考虑中
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 100005
#define mod 100000009
//#define ivorysi
using namespace std;
typedef long long ll;
const int N=10000000;
bool nonprime[N+5];
int prime[N+5],tot,func[N+5],n,m,ans,T;
int sum(int x,int y) {
return (1LL*x*(x+1)/2%mod*(1LL*y*(y+1)/2%mod))%mod;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
func[1]=1;
siji(i,2,N) {
if(!nonprime[i]) {
prime[++tot]=i;
func[i]=((i-1LL*i*i%mod)%mod+mod)%mod;
}
siji(j,1,tot) {
if(prime[j]>N/i) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) {
func[i*prime[j]]=1LL*prime[j]*func[i]%mod;
break;
}
func[i*prime[j]]=1LL*func[prime[j]]*func[i]%mod;
}
}
siji(i,1,N) func[i]+=func[i-1],func[i]%=mod;
scanf("%d",&T);
while(T--) {
ans=0;
scanf("%d%d",&n,&m);
int t=min(n,m),r;
for(int i=1;i<=t;i=r+1) {
r=min(n/(n/i),m/(m/i));
if(r>t) r=t;
ans+=1LL*sum(n/i,m/i)*(func[r]-func[i-1])%mod;
ans=(ans%mod+mod)%mod;
}
printf("%d\n",ans);
}
return 0;
}
对于任意的>1的n gcd(a, b)不是n^2的倍数
也就是说gcd(a, b)没有一个因子的次数>=2
然后求lcm(a,b)
一个正整数T表示数据组数
接下来T行 每行两个正整数 表示N、M
T行 每行一个整数 表示第i组数据的结果
4
2 4
3 3
6 5
8 3
24
28
233
178
HINT
T <= 10000
N, M<=4000000
枚举每个合法的d
然后用合法的更新它的倍数,根据调和级数,那么这是的
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long ll;
const int N=4000000;
bool nonprime[N+5];
int prime[N+5],tot,miu[N+5],n,m,ans,T,func[N+5];
int sum(int x,int y) {
return (x*(x+1)/2)*(y*(y+1)/2);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
miu[1]=1;
siji(i,2,N) {
if(!nonprime[i]) {
prime[++tot]=i;
miu[i]=-1;
}
siji(j,1,tot) {
if(prime[j]>N/i) break;
nonprime[i*prime[j]]=1;
if(i%prime[j]==0) break;
miu[i*prime[j]]=-miu[i];
}
}
siji(i,1,N) {
if(miu[i]==0) continue;
int t=i;
while(t<=N) {
func[t]+=t/i*t*miu[t/i];
t+=i;
}
}
siji(i,1,N) {func[i]+=func[i-1];}
scanf("%d",&T);
while(T--) {
ans=0;
scanf("%d%d",&n,&m);
int t=min(n,m),r;
for(int i=1;i<=t;i=r+1) {
r=min(n/(n/i),m/(m/i));
if(r>t) r=t;
ans+=sum(n/i,m/i)*(func[r]-func[i-1]);
}
printf("%d\n",ans&((1<<30)-1));
}
return 0;
}