HDU4135-Co-prime-数论(容斥原理-模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4135

题目意思:给定区间[l,r],计算出有多少数与n互质。

这个题目如果枚举,效率太低,肯定不行。这里我们要用到容斥原理计数。因为我们无法效率高的找出多少个数与之互质,但是我们可以高效的找出多少个数与之不互质。

算法复杂度O(m*2^m);

我们将数字n分解质因子。然后枚举n的约数情况,再根据容斥原理计算出重复计算的数量。最后减去便可。

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define LL long long
#define inf 1<<29
#define s(a) scanf("%d",&a)
#define CL(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=100005;
LL n,r,l;
struct node{int x,cnt;};
int p[N],is[N],np=0;
LL gcd(LL a,LL b){ return b?gcd(b,a%b):a; }     //  辗转相除法gcd
void GetPrim()          //  筛选素数(模板);
{
    is[0]=is[1]=1;
    for(int i=2;i<N;i++){
        if(!is[i]){
            p[++np]=i;
            for(int j=i*2;j<N;j+=i) is[j]=1;
        }
    }
}
vector<node> factor(LL n)   //  (动态数组)分解质因数(模板);
{
    vector<node> ans;
    node t;
    for(int i=1;p[i]*p[i]<=n;i++){
        if(n%p[i]==0){
            t.x=p[i];t.cnt=0;
            while(n%p[i]==0) t.cnt++,n/=p[i];
            ans.push_back(t);
        }
    }
    if(n!=1) t.cnt=1,t.x=n,ans.push_back(t);
    return ans;
}
LL solve()
{
    LL res=0;
    vector<node>a;
    a=factor(n);        //  获得质因数数组a;
    int m=a.size();     //  不同质因数的个数;
    for(int i=1;i<(1<<m);i++){      //  二进制枚举子集可能的情况;
        int Count=0;
        for(int j=i;j;j>>=1) Count+=j&1;    //  统计子集的个数;
        LL lcm=1;
        for(int j=0;j<m;j++){
            if(i>>j&1){
                lcm=lcm*a[j].x/gcd(lcm,a[j].x);     //  算出每个子集的最小公倍数lcm;
                if(lcm>n) break;    //  如果n除以比它大的数,为防止数据溢出,提前break;
            }
        }
        if(Count&1) res+=r/lcm-(l-1)/lcm;
        else res-=r/lcm-(l-1)/lcm;
    }
    return r-l+1-res;
}
int main()
{
    int t,Case=1;
    s(t);
    GetPrim();
    while(t--){
        scanf("%I64d%I64d%I64d",&l,&r,&n);
        printf("Case #%d: %I64d\n",Case++,solve());
    }
    return 0;
}


 

你可能感兴趣的:(HDU4135,容斥原理模板)