容斥原理 && 欧拉函数 && 抽屉原理 总结

 转载博客


(1)容斥原理 :求在区间[1,m]里有多少个数,与n互质。假设数据不超过int型。

实现过程分为两步:

1, 求出n的质因子 并保存在数组里面;

2, 求出区间[1,m]里面有多少个数与n不互质。

 

代码:

  1. #include <cstdio>  
  2. #include <cmath>  
  3. int p[10];//保存质因子  int型n不会超过10个   
  4. int k;//记录质因子个数  
  5. void getp(int n)//求出n的质因子   
  6. {  
  7.     int i;  
  8.     k = 0;//初始化  
  9.     for(i = 2; i*i <= n; i++)  
  10.     {  
  11.         if(n % i == 0)  
  12.         {  
  13.             p[k++] = i;//保存质因子   
  14.             while(n % i == 0)  
  15.             n /= i;  
  16.         }  
  17.     }  
  18.     if(n > 1) p[k++] = n;//本身是质数   
  19. }   
  20. int nop(int m)//求出区间[1,m]里面有多少个数与n不互质   
  21. {  
  22.     int top = 0;//队列顶点   
  23.     int que[10100];  
  24.     int i, j, t;  
  25.     que[top++] = -1;//队列数组保存n所有质因子任意不相同组合的乘积   
  26.     for(i = 0; i < k; i++)  
  27.     {  
  28.         t = top;//利于下面计算    
  29.         for(j = 0; j < t; j++)  
  30.         {  
  31.             que[top++] = que[j] * p[i] * (-1);//奇加偶减   
  32.         }  
  33.     }  
  34.     int sum = 0;//统计个数  
  35.     for(i = 1; i < top; i++)  
  36.     sum += m / que[i];  
  37.     return sum;  
  38. }  
  39. int main()  
  40. {  
  41.     int n, m;  
  42.     while(scanf("%d%d", &n, &m), n||m)//求区间[1,m]内有多少个数与n互质   
  43.     {  
  44.         getp(n);  
  45.         printf("%d\n", m-nop(m));  
  46.     }  
  47.     return 0;  
  48. }  

(2)欧拉函数:说白了,就是指一个数n在[1,n-1]区间有多少个数与它互质(和容斥原理一样的应用)。

比如说,euler[n] = m代表的意思是在区间[1,n-1]里面有m个数与n互质。


一些欧拉函数的性质:

性质一

对于一个质数n, φ(n)=n1 。 

性质二

n=pk ,则 φ(n)=pkpk1=(p1)pk1 。 

性质三

gcd(n,m)=1 时, φ(nm)=φ(n)φ(m)  

性质四

n=pk11pk22...pkmm ,则 φ(n)=n(11p1)(11p2)...(11pm)  

性质五

欧拉定理:对于互质的整数 a,m aφ(m)1(modm) 。 

性质六

设小于n的所有与n互质的数的和为 Sum Sum=nφ(n)2  

性质七

首先 p 是个质数。如果 imodp=0 ,那么 φ(ip)=pφ(i)  ,否则 φ(ip)=φ(i)(p-1)

性质八

直接给式子吧… 
n=d|nφ(d)  

欧拉函数详解

现给个实例:求区间[1,100]内所有数的欧拉函数,euler[1]=1

求欧拉函数 有两个思路:

1, 筛素数打表,用数组记录每个数的欧拉函数(适用于n不是很大的情况,因为数组不能开无限大);

2, 直接求法计算单个欧拉函数,对于有些题目会比较慢(对于很大的n依然可以求解)。

筛素法:

  1. #include <cstdio>  
  2. #include <cstring>  
  3. #define MAX 100+1  
  4. int eu[MAX];  
  5. void euler()  
  6. {  
  7.     int i, j;  
  8.     eu[1] = 1;//1的欧拉函数为1 看题目而定   
  9.     for(i = 2; i < MAX; i++)  
  10.     {  
  11.         if(!eu[i])  
  12.         {  
  13.             for(j = i; j < MAX; j += i)  
  14.             {  
  15.                 if(!eu[j]) eu[j] = j;  
  16.                 eu[j] = eu[j] * (i-1) / i;  
  17.             }  
  18.         }  
  19.     }  
  20. }  
  21. int main()  
  22. {  
  23.     euler();  
  24.     for(int i = 1; i < MAX; i++)  
  25.     printf("%d\n", eu[i]);  
  26.     return 0;  
  27. }  

 

计算单个欧拉函数:

 

  1. #include <cstdio>  
  2. #include <cstring>  
  3. #define MAX 100+1  
  4. int euler(int n)//求n的欧拉函数   
  5. {  
  6.     int i;  
  7.     int eu = n;//欧拉函数   
  8.     for(i = 2; i*i <= n; i++)  
  9.     {  
  10.         if(n % i == 0)//质因子   
  11.         {  
  12.             eu = eu * (i-1) / i;  
  13.             while(n % i == 0)  
  14.             n /= i;//避免再次累加   
  15.         }   
  16.     }  
  17.     if(n > 1) eu = eu * (n-1) / n;//本身就是 质数   
  18.     return eu;  
  19. }  
  20. int main()  
  21. {  
  22.     for(int i = 1; i < MAX; i++)  
  23.     printf("%d\n", euler(i));  
  24.     return 0;  
  25. }  

 

对于很多题目,容斥原理若和欧拉函数一起使用,或许会增加程序效率。


(3) 抽屉原理: 又称鸽巢原理,指的是n+1个苹果放进n个盒子里面,一定会有一个盒子有两个苹果。

定理: 一个由n个数构成的数列,总能找到若干个连续的数 使它们之和能被n整除。

证明: 对于数列里面的元素a[1],a[2],...... a[n]。我们可以构造一个数组sum[],用sum[ i ]来存储前i个元素之和(包括第i个元素)。

那么sum数组里面所有的元素只有两种情况:(1) 至少存在一个sum[ i ] 能被n整除;(2) 对于所有的sum[ i ] 都不能被n整除 。

 

情况(1):定理成立。。。

情况(2):首先我们知道sum数组里面有n个元素,又因为它们都不能被n整除,那么我们可以得到以下信息:任意的(sum[i] %n)都非0且结果都在(1到n-1范围里面)

                  这样的话--> n个结果在  1到n-1 范围内,必然存在两个相等的结果。而这两个相同结果所对应的sum[] 之差 必定能被 n整除。证毕。

对于抽屉原理,可以有以下拓展:(1) 数列里面元素个数只要大于或者等于n也成立 (2) 找到的 若干个数 不是连续的也成立。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值