HDU1659-GCD-容斥原理
从1-a和1-b种选两个数xy,计算出令gcd(x,y)=k的xy的对数。
对于每一个i∈[1,b]使用solve(i,n)函数解决有几个j∈[1,n]使gcd(x,y)=k。然后累加solve(i,n)-solve(i,i)即可,注意边界情况。
solve函数则使用容斥原理。
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 100100; int T,a,b,c,d,k; long long ans; int prime[maxn]; void init() { for(int i=2;i<=maxn;i++) { if(!prime[i]) prime[++prime[0]] = i; for(int j=1;j<=prime[0]&&prime[j]<=maxn/i;j++) { prime[prime[j]*i] = 1; if(i%prime[j]==0) break; } } } int factor[100]; int fatCnt; int getFactors(int x) { fatCnt = 0; int tmp = x; for(int i=1;prime[i]<=tmp/prime[i];i++) { if(tmp%prime[i] == 0) { factor[fatCnt] = prime[i]; while(tmp%prime[i] == 0) { tmp/=prime[i]; //factor[fatCnt] *= prime[i]; } fatCnt++; } } if(tmp != 1) { factor[fatCnt++] = tmp; } return fatCnt; } long long solve(int x,int n) { int np = getFactors(x); int cnt,lcm; long long res = n/k; //printf("x=%d n=%d np=%d \n",x,n,np); for(int i=1;i<(1<<np);i++) { cnt=0;lcm=1; int flag = 0; for(int j=0;j<fatCnt;j++) { if((1<<j) & i) { lcm *= factor[j]; cnt++; } } lcm *= k; cnt++; if(cnt&1) res += n/lcm; else res -= n/lcm; } //printf("res=%d\n",res); return res; } int main() { scanf("%d",&T); init(); for(int kase=1;kase<=T;kase++) { scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("Case %d: ",kase); if(k == 0) {printf("0\n");continue;} if(d > b) swap(d,b); ans = 0; for(int i=c;i<=d;i++) if(i%k == 0) { ans += (solve(i/k,b)-solve(i/k,i)); if(i == k) ans++; } printf("%lld\n",ans); } }