【莫比乌斯反演】[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 这样只要枚举 T T的一个质因数就可以得到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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值