HDU

Question

参考

题意
找出[a,b]中与n互质的数的个数
分析
通常我们求1~n中与n互质的数的个数都是用欧拉函数.但如果n比较大或者是求1~m中与n互质的数的个数等等问题,要想时间效率高的话还是用容斥原理。先对n分解质因数,分别记录每个质因数, 那么所求区间内与某个质因数不互质的个数就是 m/r(i),假设r(i)是r的某个质因子 假设只有三个质因子, 总的不互质的个数应该为p1+p2+p3-p1*p2-p1*p3-p2*p3+p1*p2*p3. pi代表m/r(i),即与某个质因子不互质的数的个数 ,当有更多个质因子的时候,可以用状态压缩解决,二进制位上是1表示这个质因子被取进去了。 如果有奇数个1,就相加,反之则相减

容斥原理
求事件A、B、C的交集时,A U B U C=A+B+C-AB-AC-BC+ABC

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define ull unsigned long long
#define LOCAL

using namespace std;
const int maxn=5000+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

vector<ll> v;
ll a,b,n;

void getPrime(ll n){//素数分解,要求的n较少时
    v.clear();
    for(ll i = 2;i*i<=n;i++){
        if(n%i==0){
            v.push_back(i);
            while(n%i==0) n/=i;
        }
    }
    if(n>1) v.push_back(n);
    return ;
}

ll solve(ll x,ll n){
    getPrime(n);
    ll sum=0,val,cnt;
    for(ll i=1;i<(1<<v.size());i++){
        val=1;
        cnt=0;
        for(ll j=0;j<v.size();j++){
            if((1<<j)&i){
                val*=v[j];
                cnt++;
            }
        }
        if(cnt&1) sum+=x/val;
        else sum-=x/val;
    }
    return x-sum;
}

int main(){
    int t;
    scanf("%d",&t);
    for(int i=1;i<=t;i++){

        cin>>a>>b>>n;
        printf("Case #%d: %I64d
",i,solve(b,n)-solve(a-1,n));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/7260755.html