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);

这个公式的推导是根据容斥定律求得的。具体推导可以参考离散数学的集合定律。

欧拉函数代码实现:

 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 }
View Code

容斥定律:(以后完善)
代码实现:

递归:(其中q[r]是表示,数r的质因子个数,除相同的。p[r][i]是:数r的第i个质因子。max总数。r是地r个数).

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 }
View Code

记住:要用总数减去所求得的结果;

本题代码如下:(另一种容斥定律代码的实现)

  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 } 
View Code

 

 

 

 

 

posted on 2013-05-16 21:10  青竹士  阅读(227)  评论(0编辑  收藏  举报

导航