BZOJ2820: YY的GCD

来源:互联网 发布:海盗战 知乎 编辑:程序博客网 时间:2024/04/29 15:02

BZOJ2820

直接枚举质数像1101那样做肯定会T…然而我还是不信邪的T了一发才开心。。

根据前面的题的经验。
这道题的式子可以先化成

k=1p[k]<=min(n,m)d=1min(n,m)μ(d)npkdmpkd

将式子进一步推演:
T=pd

T=1min(n,m)(nTmTd|Tμ(Td))

d|Tμ(Td)
直接枚举质数算就好了,更厉害一点可以线性筛求。

最后就分块求就好了。

【代码】

#include <cstdio>#include <iostream>#include <algorithm>#define N 10000005using namespace std;typedef long long ll;int read(){    int x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}    return x*f;}int T,n,m;int Miu[N],p[664580],sum[N];bool Not_Prime[N];void Get_Miu(){    Miu[1]=1;    for(register int i=2;i<N;i++) {        if(!Not_Prime[i]) p[++p[0]]=i,Miu[i]=-1;        for(register int j=1;j<=p[0]&&i*p[j]<N;j++)        {            Not_Prime[i*p[j]]=1;            if(i%p[j]==0) {Miu[i*p[j]]=0;break;}            Miu[i*p[j]]=-Miu[i];        }    }    for(register int i=1;i<=p[0];i++)    for(register int j=p[i];j<N;j+=p[i]) sum[j]+=Miu[j/p[i]];    for(register int i=1;i<N;i++) sum[i]+=sum[i-1];}void Calc(){    ll ans=0;int pos=1;    for(int i=1;i<=n;i=pos+1)    {        pos=min(n/(n/i),m/(m/i));        ans+=1LL*(sum[pos]-sum[i-1])*(n/i)*(m/i);    }    printf("%lld\n",ans);}int main(){    Get_Miu();    T=read();    while(T--)    {        n=read(),m=read();        if(n>m) swap(n,m);        Calc();    }    return 0;}
原创粉丝点击