【莫比乌斯反演】[BZOJ2820]YY的GCD

题目描述:
求有多少数对(x,y)(1<=x<=n,1<=y<=m)满足gcd(x,y)为质数
首先枚举一个质数发现

ans=prime(p)d=1nμ(d)npdmpd
实际上就是根据容斥原理在n/p和m/p中互质数的对数然后枚举每一个质数p
那么设T=pd 会发现实际上对于T 来说这个n/T可以为多个p 比如T=p1p2p3 那么当p=p_1的时候 d=p_2*p_3 这样只要枚举TT的一个质因数就可以得到d化简就可以得到
ans=T=1nnTmTprime(p),p|Tμ(Tp)

那么现在预处理后面的F(T)=prime(p),p|Tμ(Tp)
令当前的数为i,当前的最小质因数为p发现如果p|i那么p是i的质因子,那么μ(ip)才有可能不等于0否则p×p|i那么无论除以i其他的质因子剩下的数也只会是合数了,所以如果i|p那么F(i×p)=μ(i) 否则的话如果T×ii剩下的数字的莫比乌斯函数值一定是μ(i) 如果除以其他的质因子就会发现所有的组合都多了一个质因子的因数,那么根据分配率F(T)=μ(i)+(F(i))

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 10000000;
bool nprime[MAXN+10];
int pcnt, prime[MAXN+10], sum[MAXN+10], mu[MAXN+10];
void Init(int up = MAXN-1){
    int tmp; mu[1] = 1;
    for(int i=2;i<=up;i++){
        if(!nprime[i]){
            prime[++pcnt] = i, mu[i] = -1; sum[i] = 1;
        }
        for(int j=1;j<=pcnt&&(tmp = prime[j]*i) <= up;j++){
            nprime[tmp] = true;
            if(i % prime[j] == 0){
                mu[tmp] = 0;
                sum[tmp] = mu[i];
                break;
            }
            mu[tmp] = -mu[i];
            sum[tmp] = mu[i]-sum[i];
        }
    }
    for(int i=2;i<=up;i++)
        sum[i] += sum[i-1];
}
int main(){
    Init();
    int n, m, T;
    long long ret;
    scanf("%lld", &T);
    while(T--){
        scanf("%d %d", &n, &m);
        if(n > m) swap(n, m);
        ret = 0;
        for(int i=1, nex;i<=n;i=nex+1){
            nex = min(n/(n/i), m/(m/i));
            ret += 1LL * (n/i) * (m/i) * (sum[nex] - sum[i-1]);
        }
        printf("%lld\n", ret);
    }

    return 0;
}

posted on 2015-06-04 14:03  JeremyGuo  阅读(121)  评论(0编辑  收藏  举报

导航