bzoj2818 Gcd

来源:互联网 发布:金相分析仪 知乎 编辑:程序博客网 时间:2024/05/29 08:38

题目链接:bzoj2818
题目大意:
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.

题解:
欧拉函数或莫比乌斯反演
设d∈[1,n]是一个质数。
原式即

i=1nj=1ngcd(i,j)=d1

套路一下:
i=1nj=1ndgcd(id,jd)=11

额第三个求和是在枚举范围内的质数。

欧拉函数的做法就是化成:

di=1nj=1n[gcd(id,jd)=1]

然后看式子的后半部分,就是在求[1,n]中的与id互质的数的个数,就是ϕ(i)。所以可以预处理欧拉函数及其前缀和,枚举质数d然后直接累加就好了。

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;#define maxn 10001000#define N 701000bool ispri[maxn];LL sum[maxn];int n,cnt,phi[maxn],pri[N];void Eular(int lim){    cnt=0;phi[1]=1;    for (int i=2;i<=lim;i++)    {        if (!ispri[i]) {pri[++cnt]=i;phi[i]=i-1;}        for (int j=1;j<=cnt && pri[j]*i<=lim;j++)        {            ispri[i*pri[j]]=true;            if (i%pri[j]==0)            {                phi[i*pri[j]]=pri[j]*phi[i];                // mu[i*pri[j]]=0;                break;            }            phi[i*pri[j]]=(pri[j]-1)*phi[i];            // mu[i*pri[j]]=-mu[i];        }    }sum[0]=0;    for (int i=1;i<=lim;i++) sum[i]=sum[i-1]+phi[i];}int main(){    //freopen("a.in","r",stdin);    //freopen("a.out","w",stdout);    int n,i;LL ans=0;    scanf("%d",&n);    Eular(n);    for (i=1;i<=cnt;i++)    {        int lim=n/pri[i];        ans+=sum[lim]*2-1;    }    printf("%lld\n",ans);    return 0;}

莫比乌斯反演的做法我现在还不是很懂怎么化出来..先挖个坑
来填坑
莫比乌斯反演的做法则是化成:

di=1nj=1nϵ((id,jd))

idjd什么的换成ij
反演一下:
di=1ndj=1ndt|i,t|jμ(t)

dt=1ni=1,t|indj=1,j|tndμ(t)

实际上后半部分就是在求有多少对i,jt的倍数,然后再乘上μ(t)
所以式子就是:
dt=1nndt×ndt×μ(t)

预处理mobius函数及其前缀和,枚举质数d,然后后面的n分块求就好了。
懒得再打了。。
看这位dalao的吧,谢谢dalao的解疑。

0 0
原创粉丝点击