您的位置:首页 > 其它

HYSBZ 2818 (GCD)莫比乌斯反演

2016-10-17 00:25 337 查看
E - Gcd
Time Limit:10000MS     Memory Limit:262144KB     64bit IO Format:%lld & %llu
Submit Status Practice HYSBZ
2818

Description

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的

数对(x,y)有多少对.

Input

一个整数N

Output

如题

Sample Input

4


Sample Output

4


Hint

hint

对于样例(2,2),(2,4),(3,3),(4,2)

1<=N<=10^7

对于此题,我们有两种做法。

一:欧拉函数

题目可以转化为:  求gcd(x,y)==2     gcd(x,y)==3    gcd(x,y)==5  ...  gcd(x,y)==prime 
的对数之和


比如算gcd(x,y)==2的对数,这时y的取值只能是2,4,6,8...2*k

那么gcd(x,2)==2,gcd(x,4)==2,gcd(x,6)==2,gcd(x,8)==2 ... gcd(x,<=n中最大的且是2的倍数的数)==2的对数之和即为gcd(x,y)==2的对数

那么显然gcd(x,y)==2的答案为phi(1)+phi(2)+phi(3)+...phi(n/2)

同理可得gcd(x,y)==3的答案为phi(1)+phi(2)+phi(3)+...phi(n/3)

那么令sum(x)=phi(1)+phi(2)+phi(3)+...phi(x)

那么答案即为∑2*sum(n/prime[i])-1   (考虑(x,y)
(y,x)为两种不同的答案和 (x,x) (x,x) 算同一种答案)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e7+1000;
int prime
,phi
,cnt,n;// prime:记录质数,phi记录欧拉函数
int Min_factor
;// i的最小素因子
long long sum
;
bool vis
;
void Init()
{
cnt=0;
phi[1]=1;
int x;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime[++cnt]=i;
phi[i]=i-1;
Min_factor[i]=i;
}
for(int k=1;k<=cnt&&prime[k]*i<N;k++)
{
x=prime[k]*i;
vis[x]=true;
Min_factor[x]=prime[k];
if(i%prime[k]==0)
{
phi[x]=phi[i]*prime[k];
break;
}
else phi[x]=phi[i]*(prime[k]-1);
}
}
}
int main()
{
Init();
for(int i=1;i<N;i++)sum[i]=sum[i-1]+phi[i];
//sort(prime,prime+cnt);
while(scanf("%d",&n)==1)
{
long long ans=0;
for(int i=1;prime[i]<=n;i++)
{
int k=n/prime[i];
ans+=sum[k]*2-1;
}
printf("%lld\n",ans);
}
}


二:莫比乌斯反演(懒得写题解了,直接把草稿放上来啦2333)





#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e7+10;
LL prime[maxn],mu[maxn],sum[maxn];
bool vis[maxn];
void getmu(int n)
{
for(int i=0;i<=n;i++)mu[i]=sum[i]=0;
int tot=0;
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
prime[++tot]=i;
mu[i]=-1;
sum[i]=1;
}
for(int j=1;prime[j]*i<=n;j++)
{
int x=prime[j]*i;
vis[x]=1;
if(i%prime[j]==0)
{
mu[x]=0;
sum=mu[i];
break;
}
else
{
mu[x]=-mu[i];
sum=mu[i]-sum[i];
}
}
}
for(int i=1;i<=n;i++)sum[i]+=sum[i-1];
}
int main()
{
int n;
while(scanf("%d",&n)==1)
{
getmu(n);
LL ans=0;
for(int i=1;i<=n;i++)
{
int nxt=n/(n/i);
ans+=(sum[nxt]-sum[i-1])*(n/i)*(n/i);
i=nxt;
}
printf("%lld\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息