BZOJ3309 DZY Loves Math(莫比乌斯反演+线性筛)

  一通正常的莫比乌斯反演后,我们只需要求出g(n)=Σf(d)*μ(n/d)的前缀和就好了。

  考虑怎么求g(n)。当然是打表啊。设n=∏piai,n/d=∏pibi 。显然若存在bi>1则这个d没有贡献。考虑bi为0和1两种情况。如果只看ai最小的质因子的选取情况,会发现大部分情况下其是0还是1,对f的取值是没有影响的,但会使μ取反,于是就抵消为0。而特殊情况即为所有ai均相同,此时若所有bi都取1会使f减少。与一般情况比较可以得到此时g(n)=(-1)质因子个数+1

  然后就可以线性筛了。记录一下n去掉最小质因子后的数及最小质因子的幂次就可以了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 10000010
int T,prime[N],f[N],p[N],c[N],v[N],cnt=0;
bool flag[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj3309.in","r",stdin);
    freopen("bzoj3309.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    T=read();
    flag[1]=1;p[1]=1;c[1]=0;f[1]=0;
    for (int i=2;i<=N-10;i++)
    {
        if (!flag[i]) prime[++cnt]=i,p[i]=1,c[i]=1,f[i]=1;
        for (int j=1;j<=cnt&&prime[j]*i<=N-10;j++)
        {
            int t=prime[j]*i;
            flag[t]=1;
            if (i%prime[j]==0)
            {
                p[t]=p[i];
                c[t]=c[i]+1;
                if (c[p[i]]==0) f[t]=1;
                else f[t]=(c[t]==c[p[i]]?-f[p[i]]:0);
                break;
            }
            p[t]=i;
            c[t]=1;
            if (c[i]==0) f[t]=1;
            else f[t]=(c[i]==1?-f[i]:0);
        }
    }
    for (int i=1;i<=N-10;i++) f[i]+=f[i-1];
    while (T--)
    {
        int n=read(),m=read();
        long long ans=0;
        for (int i=1;i<=min(n,m);i++)
        {
            int t=min(n/(n/i),m/(m/i));
            ans+=1ll*(f[t]-f[i-1])*(n/i)*(m/i);
            i=t;
        }
        printf(LL,ans);
    }
    return 0;
}

 

posted @ 2018-09-20 22:27  Gloid  阅读(154)  评论(0编辑  收藏  举报