[BZOJ2693]jzptab
【题目描述】
为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中的i行的j列写着数lcm(i,j)。crash表格里所有数的和mod100000009的值。
【输入格式】
第一行输入T,表示数据组数。接下来的T行,每行输入N和M
【输出格式】
对于每个询问,输出表格中所有数的和mod100000009的值
【样例输入】
1 4 5
【样例输出】
122
【提示】
T<=10000;N,M<=10000000
先附一个链接:
https://www.cnblogs.com/yoyoball/p/8231397.html
我是直接枚举i和i的倍数j计算f()的,可以证明这样只有O(nlogn)
但是链接中运用积性函数性质用线性筛更好
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 typedef long long lol; 8 int Q[10001][2],Mod=100000009,inv2,N,tot,n,m; 9 int f[10000005],ans,mu[10000005],prime[5000005]; 10 bool vis[10000005]; 11 int get_sum(int x,int y) 12 { 13 int s1,s2; 14 s1=(1ll*(1+x)*x/2)%Mod; 15 s2=(1ll*(1+y)*y/2)%Mod; 16 return 1ll*s1*s2%Mod; 17 } 18 void pre() 19 {int i,j; 20 mu[1]=1; 21 for (i=2;i<=N;i++) 22 { 23 if (vis[i]==0) 24 { 25 ++tot; 26 prime[tot]=i; 27 mu[i]=-1; 28 } 29 for (j=1;j<=tot;j++) 30 { 31 if (1ll*i*prime[j]>N) break; 32 vis[i*prime[j]]=1; 33 if (i%prime[j]==0) 34 { 35 mu[i*prime[j]]=0; 36 break; 37 } 38 else mu[i*prime[j]]=-mu[i]; 39 } 40 } 41 for (i=1;i<=N;i++) 42 { 43 for (j=1;j<=N;j++) 44 { 45 if (1ll*i*j>N) break; 46 f[i*j]+=i*mu[i]; 47 f[i]=(f[i]+Mod)%Mod; 48 } 49 } 50 for (i=1;i<=N;i++) 51 f[i]=(1ll*f[i]*i%Mod+f[i-1])%Mod; 52 } 53 int main() 54 { 55 int T,i,j,pos; 56 cin>>T; 57 for (i=1;i<=T;i++) 58 { 59 scanf("%d%d",&Q[i][0],&Q[i][1]); 60 if (Q[i][0]>Q[i][1]) swap(Q[i][0],Q[i][1]); 61 N=max(N,Q[i][0]); 62 } 63 pre(); 64 for (j=1;j<=T;j++) 65 { 66 ans=0; 67 n=Q[j][0],m=Q[j][1]; 68 for (i=1;i<=n;i=pos+1) 69 { 70 pos=min(n/(n/i),m/(m/i)); 71 ans=(ans+1ll*get_sum(n/i,m/i)*((f[pos]-f[i-1]+Mod)%Mod)%Mod)%Mod; 72 } 73 printf("%d\n",ans); 74 } 75 }