mobius inversion

有关资料:

定义及性质证明

线性筛法

相关题目


入门题:hdu 1695

题目大意:求满足x属于区间[1,m]与y属于区间[1,n],且gcd(x,y)=k的数对(x,y)个数。(x,y)与(y,x)属于算作同一个数对。


分析:问题与求x∈[1,m/k],y∈[1,n/k]且gcd(x,y)=1数对(x,y)个数等价。。

设f(i)表示x∈[1,m/k],y∈[1,n/k]且gcd(x,y)=i的数对个数,相应地设F[i]表示x∈[1,m/k],y∈[1,n/k]且gcd(x,y)能被i整除的数对x,y个数。

显然有F[i]=sigma(f[d]) (其中d|i,即d为i的因子)

而F[i]容易求出:F[i]=[a/i][b/i]   (a=m/k,b=n/k, []表示向下取整)

于是根据莫比乌斯反演定理,有f[i]=sigma(u[d/i]]*F[d]) 其中i|d

要求的值为f[1]=sigma(u[d]*F[d])




#include <stdio.h>
#define N 100005
typedef long long LL;
int min(int a,int b) {return a<b?a:b;}
int u[N],p[N],v[N];
void init()
{
    int i,j,t=0;
    u[1]=1;
    for(i=2;i<N;++i)
    {
        if(!v[i]) p[t++]=i,u[i]=-1;
        for(j=0;j<t&&p[j]*i<N;++j)
        {
            v[p[j]*i]=1;
            if(i%p[j]==0) {u[p[j]*i]=0;break;}
            u[i*p[j]]=-u[i];
        }
    }
}

int main()
{
    int ca,n,i,t,a,b,c,d,k;
    LL ans,tmp;
    init();
    scanf("%d",&n);
    for(ca=1;ca<=n;++ca)
    {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if(!k) {printf("Case %d: 0\n",ca);continue;}   //注意k=0的时候
        tmp=ans=0;
        b/=k,d/=k;
        t=min(b,d);
        for(i=1;i<=t;++i) {tmp+=(LL)u[i]*(t/i)*(t/i);ans+=(LL)u[i]*(b/i)*(d/i);}
        ans-=tmp/2;
        printf("Case %d: %lld\n",ca,ans);
    }
    return 0;
}


另外还有bzoj 2301和这题差不多,在资料里面已经分析了。用到了分块加速

你可能感兴趣的:(mobius inversion)