bzoj2226[Spoj 5971] LCMSum
Posted OldJang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2226[Spoj 5971] LCMSum相关的知识,希望对你有一定的参考价值。
题目大意:给定T(10^5)组数据,每次给出n(10^6),求lcm(i,n){1<=i<=n}的和
一眼看上去就是一道数学题……蒟蒻数学太差思路略微诡异……我想着能不能nlogn直接把所有答案算出来,然后yy了一下……
设F[n]为所求的值,f[n]为小于n的质数的和,我们考虑到lcm(a,b)=ab/gcd(a,b),那么我们可以去枚举gcd,对于一个n的因数d,在1到n中和n最大公因数为d的数对于F[n]的贡献就显而易见了,即F[n]+=n*d*f[n/d],这样可以nlogn求出
对于f[n]求法也非常的简单,可以看出f[n]=sigma(i*[gcd(i,n)=1]),再把[gcd(i,n)=1]写成莫比乌斯函数的形式,套路一样的重新组合啊什么的,最终就是可以变成这样的形式:f[n]+=u[k]*(k*((n/k)+1)(n/k)/2){k|n},也是可以在nlogn时间求出。
听说有根号大法……不过不会……数学太弱QAQ
为了避免常数被卡特意用C++写的
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define ll long long 6 using namespace std; 7 const int N=1000086; 8 ll f[N],F[N],pri[N],vis[N],mu[N],tot; 9 int read() 10 { 11 int x=0,f=1;char ch=getchar(); 12 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 13 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 14 return x*f; 15 } 16 void getmu() 17 { 18 mu[1]=1;tot=0; 19 for(int i=2;i<=N;i++) 20 { 21 if(!vis[i]){pri[++tot]=i;mu[i]=-1;} 22 for(int j=1;j<=tot&&pri[j]*i<=N;j++) 23 { 24 vis[i*pri[j]]=1; 25 if(i%pri[j]==0){mu[pri[j]*i]=0;break;} 26 else mu[pri[j]*i]=-mu[i]; 27 } 28 } 29 } 30 void getf() 31 { 32 33 for(int i=1;i<=N;i++) 34 for(int j=1;j*i<=N;j++) 35 f[i*j]+=mu[i]*((ll)i*(j+1)*j/2); 36 } 37 void getF() 38 { 39 for(int i=1;i<=N;i++) 40 for(int j=1;j*i<=N;j++) 41 F[i*j]+=f[j]*i*j; 42 } 43 int main() 44 { 45 getmu();getf();getF(); 46 int T=read(); 47 while(T--) 48 { 49 int n=read();printf("%lld\n",F[n]); 50 } 51 return 0; 52 }
以上是关于bzoj2226[Spoj 5971] LCMSum的主要内容,如果未能解决你的问题,请参考以下文章