BZOJ2820: YY的GCD

很好的一道莫比乌斯反演
看了题解才把式子推出来
去看ioi爷的博客吧
http://www.cnblogs.com/iwtwiioi/p/4132095.html

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const
int maxn=10000001;
int mu[maxn],G[maxn];
long long Presum[maxn];
bool check[maxn];
int prime[maxn],tot;
char c;
inline void read(int &a)
{a=0;do c=getchar();while(c<'0'||c>'9');
while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}
int main()
{
    int i,j,k,l;
    memset(mu,-1,sizeof(mu));
    mu[1]=1;
    for(i=2;i<maxn;i++)
     {
      if(!check[i])
         prime[++tot]=i,mu[i]=-1,G[i]=1;
       for(j=1;j<=tot;j++) 
         {
             if(i*1ll*prime[j]>=maxn)break;
             check[i*prime[j]]=true;
             if(i%prime[j]==0){
             mu[i*prime[j]]=0,G[i*prime[j]]=mu[i];break;}
             else 
             mu[i*prime[j]]=-mu[i],G[i*prime[j]]=mu[i]-G[i];
           }      
     }   
     int Q,n,m; 
     read(Q); 
    for(i=1;i<maxn;i++)
      Presum[i]=Presum[i-1]+G[i];
    while(Q--)
    {
        read(n),read(m);
        if(m<n)swap(n,m);
        i=j=1;
        int T=1;
        int tp,Div1,Div2;
        long long ans=0;
        while(T<=n)
        {
            Div1=n/T;
            if(Div1==1)
                l=n+1;
            else l=n/Div1+1;
            Div2=m/T;
            if(Div2==1)
                k=n+1;
            else k=m/Div2+1;
            tp=min(l,k);
            ans+=Div1*1ll*Div2*(Presum[tp-1]-Presum[T-1]);
            T=tp;
         } 
         printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(gcd)