题目:GCD SUM
题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=39872
算法:莫比乌斯反演、优化
1 #include<stdio.h> 2 #define N 100001 3 typedef long long LL; 4 bool pri[N]={0}; 5 int prim[N],po=0; 6 int mu[N]; 7 LL f[N],ff[N]; //缩短时间 8 /* 9 莫比乌斯函数mu[i]的定义: 10 1. 如果 i 是素数,那么mu[i]为-1; 11 2. 如果 i 是由多个不同的素数组成的,那么mu[i]为-1或者1,取决于质因子的数量,奇数就为-1,偶数为1 12 3. 如果 i 不满上面的条件,那么mu[i]为0,比如mu[4]=0; 13 用途:想要判断1~m中有多少数与i互质,那么首先计算出i的质因子,采用容斥定理做,排除掉所有质因子的倍数,再加上被重复计算的 14 比如i=6、m=20时,首先排除2的倍数,再排除3的倍数,现在6的倍数被排除两次,就加上6的倍数数量。 15 */ 16 void Init() 17 { 18 mu[1]=1; 19 for(int i=2;i<N;i++) 20 { 21 if(!pri[i]) 22 { 23 prim[po++]=i; 24 mu[i]=-1; 25 } 26 for(int j=0;j<po;j++) 27 { 28 LL tmp=i*prim[j]; 29 if(tmp>=N) break; 30 pri[tmp]=1; 31 mu[tmp]=mu[i]*-1; 32 if(i%prim[j]==0) 33 { 34 mu[tmp]=0; 35 break; 36 } 37 } 38 } 39 f[0]=ff[0]=0; 40 //f[]:mu的前缀和 41 for(int i=1;i<N;i++) 42 { 43 f[i]=f[i-1]+mu[i]; 44 ff[i]=ff[i-1]+mu[i]*i; 45 } 46 } 47 int min(int n,int m) 48 { 49 return n>m?m:n; 50 } 51 int main() 52 { 53 Init(); 54 int n,m; 55 while(scanf("%d%d",&n,&m)!=EOF) 56 { 57 LL ans=0,ansx=0,ansy=0; 58 int t=min(n,m); 59 int j=1; 60 /* 61 简化前: 62 for(int i=1;i<=t;i++) 63 { 64 ans+=mu[i]*(n/i)*(m/i); 65 可简化原因:(n/i)*(m/i)虽然i一直在变化,但很多时候是相等的,比如15/8等于1,一直到15/15还是等于1。。。 66 ansx+=mu[i]*(m/i)*(i+(n/i)*i)*(n/i)/2; 67 ... 68 } 69 n/i:得到值,随着i的增大,如果这个值一直不变,那么这些可以和在一起算。 70 n/(n/i):得到上面值得最大i,从上面的i到现在的i=n/(n/i),之间的n/i,都等于n/i 71 */ 72 for(int i=1;i<=t;i=j+1) 73 { 74 j=min(n/(n/i),m/(m/i)); 75 ans+=(f[j]-f[i-1])*(n/i)*(m/i); 76 ansx+=(ff[j]-ff[i-1])*(m/i)*(1+(n/i))*(n/i)/2; 77 ansy+=(ff[j]-ff[i-1])*(n/i)*(1+(m/i))*(m/i)/2; 78 } 79 printf("%lld %lld %lld\n",ans,ansx,ansy); 80 } 81 return 0; 82 }