HDU-1695,欧拉函数,容斥定律。
题意:给出x的范围(a,b),y的范围(c,d),在给出k。求满足gcd(x,y)=k的个数。x,y,范围不会超出100000,并且,a=c。
如果gcd(x,y)=k,那么,gcd(x/k,y/k)=1,这就意味着,在区间(1,b/k),(1,d/k)有多小个数互质。这样,我们就有点思路了。我们大概了解欧拉函数。
它是求前n-1个数与第个n数互质的个数。它有一个公式,简单讲述一下。
一个合数可以分成若个质因子相乘。比如12=2*2*3*.由于2与2是相等的。变为合理的是12=3*2^2;那么对于任意一个数n,它可以写成n=(p1^k1)*(p2^k2)*p3.....(pi^kx).
p1,p2..pi,它们是彼此不相等的。那么欧拉函数的公式:
f(n)=n(1-1/p1)(1-1/p2)......(1-1/pi);
这个公式的推导是根据容斥定律求得的。具体推导可以参考离散数学的集合定律。
欧拉函数代码实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int eular(int n) 2 { 3 int ret=1,i; 4 for(i=2;i*i<=n;i++) 5 { 6 if(n%i==0) 7 { 8 n/=i; 9 ret*=i-1; 10 while(n%i==0) 11 n/=i,ret*=i; 12 } 13 } 14 if(n>1) ret*=n-1; 15 return ret; 16 }
容斥定律:(以后完善)
代码实现:
递归:(其中q[r]是表示,数r的质因子个数,除相同的。p[r][i]是:数r的第i个质因子。max总数。r是地r个数).
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 INT DFS(int h,long max,int r) 2 { 3 INT ans=0; 4 for(int i=h;i<q[r];i++) 5 { 6 ans+=max/p[r][i]-DFS(i+1,max/p[r][i],r); 7 } 8 return ans; 9 }
记住:要用总数减去所求得的结果;
本题代码如下:(另一种容斥定律代码的实现)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <memory.h> 3 #include<math.h> 4 #include <vector> 5 using namespace std; 6 typedef long long LL; 7 8 const int N = 100005; 9 10 LL phi[N],prime[N]; 11 bool vis[N+1]; 12 13 vector<LL> stack[N]; 14 15 void get_prime() //筛选素数 16 { 17 int i,j,m,c=0; 18 m=(int)sqrt(N+0.5); 19 memset(vis,false,sizeof(vis)); 20 for(i=2;i<=m;i++) 21 if(!vis[i]) 22 { 23 for(j=i*i;j<=N;j+=i) 24 vis[j]=true; 25 } 26 for(i=2;i<=N;i++) 27 if(!vis[i]) 28 prime[c++]=i; 29 } 30 31 32 void get_PHI() // 求欧拉函数 33 { 34 int i,j; 35 for (i = 1; i <= N; i++) phi[i] = i; 36 for (i = 2; i <= N; i += 2) phi[i] /= 2; 37 for (i = 3; i <= N; i += 2) if(phi[i] == i) 38 { 39 for (j = i; j <= N; j += i) 40 phi[j] = phi[j] / i * (i - 1); 41 } 42 } 43 44 void init() //求n的质因数 45 { 46 LL i, j, k; 47 for(i = 1; i < N; i++) 48 { 49 k = i; 50 for(j = 0; prime[j]*prime[j] <= k; j++) 51 { 52 if(k%prime[j] == 0) 53 { 54 stack[i].push_back(prime[j]); 55 while(k%prime[j] == 0) 56 k /= prime[j]; 57 } 58 if(k == 1) break; 59 } 60 if(k > 1) stack[i].push_back(k); 61 } 62 } 63 64 LL get_ans(LL num,LL n) //容斥原理 65 { 66 LL ans=0,tmp,i,j,flag; 67 for(i=1;i<(LL)(1<<stack[n].size());i++) 68 { 69 tmp=1,flag=0; 70 for(j=0;j<stack[n].size();j++) 71 if(i&((LL)(1<<j))) 72 { 73 flag++; 74 tmp*=stack[n][j]; 75 } 76 if(flag&1) //奇加偶减 77 ans+=num/tmp; 78 else 79 ans-=num/tmp; 80 } 81 return ans; 82 } 83 84 int main() 85 { 86 LL i, a, b, c, d, k, sum, t, ca= 1; 87 get_prime(); 88 get_PHI(); 89 init(); 90 scanf("%I64d", &t); 91 while(t--) 92 { 93 scanf("%I64d %I64d %I64d %I64d %I64d", &a, &b, &c, &d, &k); 94 if(k == 0 || k > b || k > d) 95 { 96 printf("Case %I64d: 0\n", ca++); 97 continue; 98 } 99 if(b > d) swap(b, d);//保持d较大 100 b /= k; 101 d /= k; 102 sum = 0; 103 for(i = 1; i <= b; i++) 104 { 105 sum += phi[i]; 106 } 107 for(i = b+1; i <= d; i++) 108 { 109 sum += b - get_ans(b, i); 110 } 111 printf("Case %I64d: %I64d\n", ca++, sum); 112 } 113 return 0; 114 }