hdu 1695 GCD 【容斥原理】
阿新 • • 發佈:2018-12-07
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1695
題目大意:求(1,b)區間和(1,d)區間裡面gcd(x, y) = k的數的對數(1<=x<=b , 1<= y <= d)。
思路:讓x,y都除上k,就是求gcd(x,y)=1的對數,gcd=1就是兩個數互質,那麼問題就可以轉換成在(1,b/k)和(1,d/k)中互質的數的對數,題意告訴(1,3)和(3,1)為一種情況,所以限制x<=y即可;
要預處理求出所有數的素因數;
答案很大,用long long 記錄答案;
#include<stdio.h> #include<string.h> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<set> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int N=1e5+4; vector<int>prime[N]; int vis[N]; void get_prime()//得到所有數的素因數 { memset(vis,0,sizeof(vis)); for(int i=0;i<N-1;++i) prime[i].clear(); for(int i=2;i<N-1;i+=2) prime[i].push_back(2); for(int i=3;i<N-1;i+=2) { if(!vis[i]) { for(int j=i;j<N-1;j+=i) { vis[j]=1; prime[j].push_back(i); } } } } int solve(int n,int m) { int sum=0; for(int i=1; i<(1<<prime[m].size()); ++i) { int k=0,pa=1; for(int j=0; j<prime[m].size(); ++j) { if(i&(1<<j)) { k++; pa*=prime[m][j]; } } int cur=n/pa; if(k&1) sum+=cur; else sum-=cur; } return sum; } int main() { get_prime(); int a,b,c,d,k; int T,cas=0; scanf("%d",&T); while(T--) { 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 t=min(i,b);//如果此時i<b,就是求區間[1,i]中與i互質的數, ans+=t; //否則就是求區間[1,b]中與i互質的數,因為是為了時x<=y; ans-=solve(t,i);//1~t之間與i互素的數的個數 } printf("Case %d: %lld\n",++cas,ans); } return 0; }