[BZOJ]2226: [Spoj 5971] LCMSum 欧拉函数(或莫比乌斯反演)
2017-12-30 10:18
645 查看
Description
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.
有这个结论就很简单了:小于等于n且与n互质的数的和,然后就可以O(nlogn)预处理出所有的答案。(n+n2+n3....+1)是O(nlogn)的。
做法二:
莫比乌斯反演。
大力推式子:
ansn=∑i=1nlcm(n,i)=∑i=1nn×igcd(n,i)枚举最大公约数d,设F(x)为<=x且与x互质的数的和,很容易推出以下式子:ansn=∑d|nF(nd)×n然后考虑如何求F(x)。F(x)=∑i=1x[gcd(x,i)==1?1:0]×i然后就是莫比乌斯反演的基本变形:F(x)=∑i=1xi×∑d|gcd(x,i)μ(d)F(x)=∑i=1xi×∑d|x且d|iμ(d)然后将式子变为枚举d,考虑每个μ(d)对答案的贡献:F(x)=∑d|xμ(d)×sum(d,⌊xd⌋×d,d)上面的sum(l,r,c)表示首项为l,末项为r,公差为c的等差数列的和。
然后就可以通过枚举因数来预处理出F和ans,复杂度也是O(nlogn)的,但是多了点常数,竟然是20s卡过的……
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.
题解:
做法一:有这个结论就很简单了:小于等于n且与n互质的数的和,然后就可以O(nlogn)预处理出所有的答案。(n+n2+n3....+1)是O(nlogn)的。
做法二:
莫比乌斯反演。
大力推式子:
ansn=∑i=1nlcm(n,i)=∑i=1nn×igcd(n,i)枚举最大公约数d,设F(x)为<=x且与x互质的数的和,很容易推出以下式子:ansn=∑d|nF(nd)×n然后考虑如何求F(x)。F(x)=∑i=1x[gcd(x,i)==1?1:0]×i然后就是莫比乌斯反演的基本变形:F(x)=∑i=1xi×∑d|gcd(x,i)μ(d)F(x)=∑i=1xi×∑d|x且d|iμ(d)然后将式子变为枚举d,考虑每个μ(d)对答案的贡献:F(x)=∑d|xμ(d)×sum(d,⌊xd⌋×d,d)上面的sum(l,r,c)表示首项为l,末项为r,公差为c的等差数列的和。
然后就可以通过枚举因数来预处理出F和ans,复杂度也是O(nlogn)的,但是多了点常数,竟然是20s卡过的……
代码(做法一):
#include<bits/stdc++.h> using namespace std; #define LL long long #define pa pair<int,int> const int Maxn=1000010; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } int prime[Maxn>>1],len=0; LL phi[Maxn],ans[Maxn],sum[Maxn]; bool mark[Maxn]; void pre() { memset(mark,false,sizeof(mark)); phi[1]=1; for(int i=2;i<=1000000;i++) { if(!mark[i]){prime[++len]=i;phi[i]=i-1;} for(int j=1;j<=len&&prime[j]*i<=1000000;j++) { mark[prime[j]*i]=true; if(i%prime[j]==0) { phi[prime[j]*i]=prime[j]*phi[i]; break; } phi[prime[j]*i]=(prime[j]-1)*phi[i]; } } sum[1]=1; for(int i=2;i<=1000000;i++)sum[i]=phi[i]*(LL)(i)/2LL; for(int i=1;i<=1000000;i++) for(int j=i;j<=1000000;j+=i) ans[j]+=sum[i]; for(int i=1;i<=1000000;i++)ans[i]*=(LL)(i); } int main() { pre(); int T=read(); while(T--)printf("%lld\n",ans[read()]); }
代码(做法二):
#include<bits/stdc++.h> using namespace std; #define LL long long #define pa pair<int,int> const int Maxn=1e6+10; const int inf=1e6; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } int prime[Maxn],len=0,mu[Maxn]; bool mark[Maxn]; LL F[Maxn],ans[Maxn]; LL Sum(LL l,LL r,LL c) { LL x=(r-l)/c+1; return (l+r)*x/2LL; } void pre() { memset(F,0,sizeof(F)); memset(ans,0,sizeof(ans)); memset(mark,false,sizeof(mark)); mu[1]=1; for(int i=2;i<=inf;i++) { if(!mark[i])prime[++len]=i,mu[i]=-1; for(int j=1;j<=len&&prime[j]*i<=inf;j++) { mark[prime[j]*i]=true; if(i%prime[j]==0){mu[prime[j]*i]=0;break;} mu[prime[j]*i]=-mu[i]; } } for(int d=1;d<=inf;d++) for(int x=d;x<=inf;x+=d) F[x]+=(LL)(mu[d]*Sum(d,(x/d)*d,d)); for(int d=1;d<=inf;d++) for(int x=d;x<=inf;x+=d) ans[x]+=F[x/d]*(LL)(x); } int main() { pre(); int T=read(); while(T--)printf("%lld\n",ans[read()]); }
相关文章推荐
- 【BZOJ2226】[Spoj 5971] LCMSum 莫比乌斯反演(欧拉函数?)
- bzoj 2226: [Spoj 5971] LCMSum 数学+欧拉函数
- [欧拉函数] BZOJ 2226 [Spoj 5971] LCMSum
- 【bzoj2226】[Spoj 5971] LCMSum 欧拉函数
- [bzoj2226][Spoj 5971] LCMSum
- BZOJ 2226: [Spoj 5971] LCMSum(数论+欧拉函数)
- BZOJ 2226 Spoj 5971 LCMSum 数论
- BZOJ 2226 [Spoj 5971] LCMSum 数论
- bzoj 2226: [Spoj 5971] LCMSum线性筛欧拉函数
- BZOJ 2226 [Spoj 5971] LCMSum 最大公约数之和 | 数论
- BZOJ2226: [Spoj 5971] LCMSum
- BZOJ 2226 【SPOJ 5971】 LCMSum
- bzoj 2226: [Spoj 5971] LCMSum 数论
- [BZOJ2226][Spoj 5971] LCMSum(莫比乌斯反演)
- bzoj 2226: [Spoj 5971] LCMSum (反演)
- BZOJ 2226 [Spoj 5971] LCMSum | 数论拆式子
- SPOJ 5971 LCM Sum 欧拉函数 (或 莫比乌斯反演?)
- bzoj 2226 LCMSum 欧拉函数
- BZOJ 2226: [Spoj 5971] LCMSum( 数论 )
- [bzoj2226][Spoj5971]LCMSum_欧拉函数_线性筛