BZOJ 3309 DZY Loves Math ——莫比乌斯反演

枚举$d=gcd(i,j)$

然后大力反演

——来自Popoqqq的博客。

然后大力讨论后面的函数的意义即可。

http://blog.csdn.net/popoqqq/article/details/42122413

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define maxn 10000005
#define inf 0x3f3f3f3f
 
int g[maxn],pr[maxn],top,a[maxn],b[maxn];
bool vis[maxn];
 
void init()
{
    memset(vis,false,sizeof vis);
    F(i,2,maxn-1)
    {
        if (!vis[i])
        {
            pr[++top]=i;
            g[i]=1;
            a[i]=1;
            b[i]=i;
        }
        F(j,1,top)
        {
            if ((ll)i*pr[j]>=maxn) break;
            vis[i*pr[j]]=true;
            if (i%pr[j]==0)
            {
                a[i*pr[j]]=a[i]+1;
                b[i*pr[j]]=b[i]*pr[j];
                int tmp=i/b[i];
                if (tmp==1) g[i*pr[j]]=1;
                else g[i*pr[j]]=(a[tmp]==a[i*pr[j]])?-g[tmp]:0;
                break;
            }
            a[i*pr[j]]=1;
            b[i*pr[j]]=pr[j];
            g[i*pr[j]]=(a[i]==1?-g[i]:0);
        }
    }
    F(i,2,maxn-1) g[i]=g[i-1]+g[i];
}
 
int t,n,m;
 
int main()
{
    init();
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);ll ans=0;
        if (n>m) n^=m^=n^=m;
        for (int i=1,last=0;i<=n;i=last+1)
        {
            last=min(n/(n/i),m/(m/i));
            ans+=((ll)g[last]-g[i-1])*(n/i)*(m/i);
        }
        printf("%lld\n",ans);
    }
}

  

posted @ 2017-03-30 19:35  SfailSth  阅读(176)  评论(0编辑  收藏  举报