HDU 1695 GCD#容斥原理
http://acm.hdu.edu.cn/showproblem.php?pid=1695
翻译题目:给五个数a,b,c,d,k,其中恒a=c=1,x∈[a,b],y∈[c,d],求有多少组(x,y)满足GCD(x,y)=k? //(x,y)和(y,x)视作同一个
题解:既然是要x,y的最大公约数为k,那说明x/k和y/k是互质的,只需在[1,b/k]和[1,d/k]范围内找到适合的x,y即可。
特判:当k等于0时,显然没有符合的,输出结果0;
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; typedef long long ll; vector<int> v; ll solve(int l,int r,int n) //[l,r]内与n互素的数字个数 { v.clear(); //筛选素数 for(int 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); //容斥原理的二进制解法 int len=v.size(); ll res=0; for(int i=1;i<(1<<len);i++) { int cnt=0; ll val=1; for(int j=0;j<len;j++) { if(i&(1<<j)) { cnt++; val*=v[j]; } } if(cnt&1) //若为奇数项进行加法,偶数项进行减法 res+=r/val-(l-1)/val; else res-=r/val-(l-1)/val; } return r-l+1-res; } int main() { int t; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { int b,d,k; scanf("%*d%d%*d%d%d",&b,&d,&k);//默认a=c=1所以不必要输入a c if(k==0) { printf("Case %d: 0\n",cas); continue; } b/=k;d/=k; if(b>d) swap(b,d); ll ans=0; for(int i=1;i<=b;i++) { int tmp=i; ans+=solve(i,d,tmp); } printf("Case %d: %I64d\n",cas,ans); } return 0; }