HDU - 1695 GCD (容斥+枚举)
题意:求区间1<=i<=b与区间1<=j<=d之间满足gcd(i,j) = k 的数对 (i,j) 个数。(i,j)与(j,i) 算一个。
分析:gcd(i,j)=k可以转化为gcd(i/k,j/k)=1。枚举每个1<=i<=b/k 的 i,用容斥原理统计区间[1,d]中与其互素的个数。需要预处理筛出2~1e5中每个数的质因子。
*注意当k=0时,数对不存在。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn =1e5+5; vector<int> p[maxn]; bool is[maxn]; void pre() { for(int i=2;i<maxn;i+=2) { p[i].clear(); p[i].push_back(2); } for(int i=3;i<maxn;i+=2){ if(is[i]) continue; for(int j=i;j<maxn;j+=i){ is[j] = true; p[j].push_back(i); } } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif pre(); int T,cas=1; scanf("%d",&T); while(T--){ int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 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<=d;++i){ int tot = min(i,b); ans += tot; int up = 1<<p[i].size(),len = p[i].size(); for(int j=1;j<up;++j){ int cnt=0,ji=1; for(int k=0;k<len;++k){ if(j&(1<<k)){ cnt++; ji *=p[i][k]; } } if(cnt&1) ans -= tot/ji; else ans +=tot/ji; } } printf("Case %d: %lld\n",cas++,ans); } return 0; }
为了更好的明天