hdu 1695GCD<容斥>
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695
题意: 在1~a, 1~b中挑出(x,y)满足gcd(x,y) = k , 求(x,y) 的对数 , a,b<=10^5
思路: gcd(x, y) == k 说明x,y都能被k整除. 问题就可以转化为了求1~a/k 和 1~b/k间互质对数的问题;
我们让b>=a; 然后在[1....b/k]进行枚举,对于每一个i,我们只要在1...min(i-1,a)中找到与i互质数,记录个数,然后累加就得到结果了;
当i<=a/k时,我们可以直接用欧拉函数计算出与i互质的个数;
当i>a/k时,先将i质因数分解,求得[1,2,...,b/k] 里所有能被x的质因数整除的数的个数,即不互质的数的个数,然后用b/k减去即可;
而 我们枚举i的质因数利用容斥原理, 容斥原理的具体如下:
区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的成绩的倍数个数)-(区间中i的每4个质因数的乘积)+...
View Code
1 #include<iostream> 2 #include <cstdio> 3 using namespace std; 4 const int Max=100005; 5 __int64 elur[Max];//存放每个数的欧拉函数值 6 int num[Max];//存放数的素因子个数 7 int p[Max][20];//存放数的素因子 8 void init()//筛选法得到数的素因子及每个数的欧拉函数值 9 { 10 elur[1]=1; 11 for(int i=2;i<Max;i++) 12 { 13 if(!elur[i]) 14 { 15 for(int j=i;j<Max;j+=i) 16 { 17 if(!elur[j]) 18 elur[j]=j; 19 elur[j]=elur[j]*(i-1)/i; 20 p[j][num[j]++]=i; 21 } 22 } 23 elur[i]+=elur[i-1]; //进行累加(法里数列长度) 24 } 25 } 26 int dfs(int idx,int b,int now)//求不大于b的数中,与now不互质的数的个数; 27 { //dfs()写的容斥原理 28 int ans=0; 29 for(int i=idx;i<num[now];i++)//容斥原理来求A1并A2并A3.....并Ak的元素的数的个数. 30 ans += b/p[now][i]-dfs(i+1,b/p[now][i],now); 31 return ans; 32 } 33 34 int main() 35 { 36 int t,a,b,c,d,k; 37 init(); 38 scanf("%d",&t); 39 for(int ca=1;ca<=t;ca++) 40 { 41 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 42 printf("Case %d: ",ca); 43 if(k==0) 44 { 45 printf("0\n"); 46 continue; 47 } 48 if(b>d) 49 swap(b,d); 50 b/=k; d/=k; 51 __int64 ans=elur[b]; 52 for(int i=b+1;i<=d;i++) 53 ans+=b-dfs(0,b,i);//求不大于b的数中,与i不互质的数的个数 54 printf("%I64d\n",ans); 55 } 56 return 0; 57 }