1. 程式人生 > >[BZOJ2693]jzptab

[BZOJ2693]jzptab

題目 i++ www. 最小公倍數 ash tar string 枚舉 com

【題目描述】

為了研究最小公倍數,他畫了一張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 }

[BZOJ2693]jzptab