GCD HDU - 1695 (容斥原理)
GCD
题意:给你5个数a,b,c,d,k。x属于[a,b]y属于[c,d]。 问你有多少对(x,y)的公约数为k。 注意(x,y)和 (y,x)视为同一对,a和c为1。
通过b/k,d/k,等价于把区间除以k,那么就变成了求有多少对(x,y)互素。
欧拉函数+容斥原理。
注意k可能为0.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=100010; 5 vector<int> pri[maxn]; 6 int que[maxn]; 7 int phi[maxn]; 8 void get_phi(){ 9 memset(phi,0,sizeof(phi)); 10 phi[1]=1; 11 for(int i=2;i<maxn;i++)if(!phi[i]){ 12 for(int j=i;j<maxn;j+=i){ 13 if(!phi[j]) phi[j]=j; 14 phi[j]=phi[j]/i*(i-1); 15 } 16 } 17 // for(int i=1;i<=20;i++) cout<<phi[i]<<endl; 18 } 19 void init(){ 20 for(int i=2;i<maxn;i++){ 21 pri[i].clear(); 22 int temp=i; 23 for(int j=2;j*j<=i;j++) if(temp%j==0){ 24 pri[i].push_back(j); 25 while(temp%j==0) temp/=j; 26 } 27 if(temp>1) pri[i].push_back(temp); 28 } 29 } 30 ll solve(int n,int s){ 31 int cnt=0; 32 que[cnt++]=1; 33 for(int i=0;i<pri[s].size();i++){ 34 int v=pri[s][i]; 35 if(v>n) break; 36 int k=cnt; 37 for(int j=0;j<k;j++){ 38 que[cnt++]=que[j]*v*(-1); 39 } 40 } 41 ll sum=0; 42 for(int i=0;i<cnt;i++) sum+=n/que[i]; 43 return sum; 44 } 45 46 int main(){ 47 int t,kase=0; 48 get_phi(); 49 init(); 50 scanf("%d",&t); 51 while(t--){ 52 printf("Case %d: ",++kase); 53 int a,b,c,d,k; 54 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 55 if(!k) {puts("0");continue;} 56 b/=k;d/=k; 57 if(b>d) swap(b,d); 58 ll ans=0; 59 for(int i=1;i<=b;i++) ans+=phi[i]; 60 for(int i=b+1;i<=d;i++) ans+=solve(b,i); 61 printf("%lld\n",ans); 62 } 63 }