【HDU】4135 - Co-prime(容斥原理)
2016-07-22 20:30
405 查看
点击打开题目
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3495 Accepted Submission(s): 1381
Problem Description
Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.
Input
The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 1015) and (1 <=N <= 109).
Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.
Sample Input
2
1 10 2
3 15 5
Sample Output
Case #1: 5
Case #2: 10
HintIn the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.
Source
The Third Lebanese Collegiate Programming
Contest
这道题确实应该好好的写一篇题解了。
如果是求小于 n 且与 n 互质的数的个数,可以用欧拉函数解决,但是这道题a,b的范围可能大于 k ,所以应该这么用容斥原理来做:
求 1~a-1 中与 k 互质的数,再求 1 ~ b 中与 k 互质的数,后者减去前者就是答案。
然后就是求 1 ~ n 中与 k 互质的数有多少,我们可以反着,先求 1 ~ n 中与 k 不互质的数有多少。
这点求法再拉出来细说:先把 k 分解质因数,存在一个数组中。
举个例子,比如 k 的质因子有 2,3,5。那么2、3、5的倍数都不和 k 互质,另外还没有完,可能有重复的地方,比如6,既是2的倍数又是3的倍数,前面用 k/2 + k/3 的时候多减了,这个时候要加上 k / (2*3)。同理,10,15这一类数都应该加上。但是还有类似于30这样的数,它是2,3,5的倍数,减的时候又多减了。
然后我们会发现,出现奇数个数,就用加法,偶数个数用减法。
最后的式子是这样的:k / 2 + k / 3 + k / 5 - k / (2 * 3) - k / (3 * 5) - k / (2 * 5) + k / (2 * 3 * 5)
有点长,看一下容易发现我说的奇偶的规律。
但是要怎么取算这个又出现问题了。
这里提供二进制的方法,个人觉得比较好理解。
设质因数的个数为m。
有一个浮动的数字,从1 ~ m依次递增,它的二进制的每一位表示用了哪些数字,比如5(101),其二进制的第一位和第三位(倒着数)是1,则它表示用了第一个质因数和第三个质因数。就是这个意思,这样就能发现:从1到m遍历一遍,就把所有的可能都包括了。
写的挺累的,有错误谢谢指正,转载说明出处。
下面看一下代码理解一下:
Co-prime
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3495 Accepted Submission(s): 1381
Problem Description
Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.
Input
The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 1015) and (1 <=N <= 109).
Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.
Sample Input
2
1 10 2
3 15 5
Sample Output
Case #1: 5
Case #2: 10
HintIn the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.
Source
The Third Lebanese Collegiate Programming
Contest
这道题确实应该好好的写一篇题解了。
如果是求小于 n 且与 n 互质的数的个数,可以用欧拉函数解决,但是这道题a,b的范围可能大于 k ,所以应该这么用容斥原理来做:
求 1~a-1 中与 k 互质的数,再求 1 ~ b 中与 k 互质的数,后者减去前者就是答案。
然后就是求 1 ~ n 中与 k 互质的数有多少,我们可以反着,先求 1 ~ n 中与 k 不互质的数有多少。
这点求法再拉出来细说:先把 k 分解质因数,存在一个数组中。
举个例子,比如 k 的质因子有 2,3,5。那么2、3、5的倍数都不和 k 互质,另外还没有完,可能有重复的地方,比如6,既是2的倍数又是3的倍数,前面用 k/2 + k/3 的时候多减了,这个时候要加上 k / (2*3)。同理,10,15这一类数都应该加上。但是还有类似于30这样的数,它是2,3,5的倍数,减的时候又多减了。
然后我们会发现,出现奇数个数,就用加法,偶数个数用减法。
最后的式子是这样的:k / 2 + k / 3 + k / 5 - k / (2 * 3) - k / (3 * 5) - k / (2 * 5) + k / (2 * 3 * 5)
有点长,看一下容易发现我说的奇偶的规律。
但是要怎么取算这个又出现问题了。
这里提供二进制的方法,个人觉得比较好理解。
设质因数的个数为m。
有一个浮动的数字,从1 ~ m依次递增,它的二进制的每一位表示用了哪些数字,比如5(101),其二进制的第一位和第三位(倒着数)是1,则它表示用了第一个质因数和第三个质因数。就是这个意思,这样就能发现:从1到m遍历一遍,就把所有的可能都包括了。
写的挺累的,有错误谢谢指正,转载说明出处。
下面看一下代码理解一下:
#include <cstdio> int p[1000000]; int num; __int64 a,b,k; void pr(int x) //求x的质因子 { num = 0; for (int i = 2 ; i * i <= x ; i++) { if (x % i == 0) { p[num++] = i; while (x % i == 0) x /= i; } } if (x > 1) p[num++] = x; } __int64 solve(__int64 n) //1~n中不与k互质的数 { __int64 ans = 0; for (__int64 i = 1; i < (__int64)1 << num ; i++) //其二进制位为1,表示这些质因数被用到 { int ant = 0; //用奇数个质因数加,偶数个减 __int64 t = 1; for (int j = 0 ; j < num ; j++) { if (((__int64)1 << j) & i) { t *= p[j]; ant++; } } if (ant & 1) //奇数加 ans += n / t; else ans -= n / t; } return ans; } int main() { int u; int Case = 1; scanf ("%d",&u); while (u--) { scanf ("%I64d %I64d %I64d",&a,&b,&k); pr(k); printf ("Case #%d: ",Case++); printf ("%I64d\n",b-(a-1)-(solve(b)-solve(a-1))); } return 0; }
相关文章推荐
- 魏传之长坂逆袭
- 基于MVC+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
- Doing Homework again hd 17892
- POJ-1328 Radar Installation
- 定义一个员工类,自己分析出几个成员,
- 【SSH网上商城】——框架
- Place the Robots(二部图最大匹配,建图,匈牙利DFS增广)
- hdu 5723(最小生成树)
- 8086汇编语言自学经验分享 新手入门的汇编源代码
- php 2038年问题
- C#编程.面向对象编程.可删除对象(Using{})
- POJ1995
- TIANKENG’s restaurant hd 4883
- dp整数划分问题——03:复杂的整数划分问题
- Flux/Redux架构初步
- FFmpeg应用程序的使用
- hdu5729 Rigid Frameworks(连通二分图计数dp)
- 使用 screen 管理远程会话
- Lars Knoll 宣布了Qt 5有四大目标
- ****Codeforces Round #363 (Div. 2) C. Vacations(DP 动态规划)