HDU 4135 Co-prime(容斥:二进制解法)题解

题意:给出[a,b]区间内与n互质的个数

思路:如果n比较小,我们可以用欧拉函数解决,但是n有1e9。要求区间内互质,我们可以先求前缀内互质个数,即[1,b]内与n互质,求互质,可以转化为求不互质,也就是有除1的公因数。那么我们把n质因数分解,就能算出含某些公因数的不互质的个数。因为会重复,所以容斥解决。因为因数个数可能很多(随便算了一个20!> 2e18,所以质因数分解个数不会超过20个),我们可以用二进制来遍历解决。

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 20000 + 10;
const int seed = 131;
const int MOD = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
ll y[5000], cnt;
ll a, b, n;
ll solve(ll num){
    ll sum = 0, val, tot;
    for(ll i = 1; i < (1 << cnt); i++){ //这里是小于最多只能cnt位
        val = 1;
        tot = 0;
        for(ll j = 0; j < cnt; j++){
            if(i & (1 << j)){   //第j个因子被用到
                val *= y[j];
                tot++;
            }
        }
        if(tot & 1){
            sum += num / val;
        }
        else{
            sum -= num / val;
        }
    }
    return num - sum;
}
int main(){
    int T, Case = 1;
    scanf("%d", &T);
    while(T--){
        scanf("%lld%lld%lld", &a, &b, &n);
        cnt = 0;
        ll x = n;
        for(ll i = 2; i * i <= x; i++){
            if(x % i == 0){
                y[cnt++] = i;
                while(x % i == 0){
                    x /= i;
                }
            }
        }
        if(x > 1){
            y[cnt++] = x;
        }
        printf("Case #%d: %lld
", Case++, solve(b) - solve(a - 1));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/9559724.html