您的位置:首页 > 其它

[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卡过的……

代码(做法一):

#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()]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: