题目链接: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; }