Co-prime
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6704 Accepted Submission(s): 2653
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.
题意:
找出A到B范围内与N互质数的个数
比如1-10中和2互质的个数为: 1 3 5 7 9 为五个
容斥原理:
在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
举个例子:
如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类元素个数+C类元素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类又是C类的元素个数+既是A类又是B类而且是C类的元素个数A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C
就是A与B与C并集 = A中元素和B和C中的所有元素 除去A和B的交集 除去B和C的交集 除去C和A的交集 再加上A和B和C的交集
我们可以先求出 1——(A-1)范围内与N互质的个数,然后在算出1——B中与N互质的个数,再利用容斥原理求出A——B中与N互质的个数。
比如对于样例2
1——2中与5互质的数有 1,2 有2个
1——15中与5互质的数有 1,2,3,4,6,7,8,9,11,12,13,14 有12个
根据容斥原理 3——15中与 5 互质的个数为 ( 12+2) -2 -2 + 2 为十个
再举个例子 比如6——15中与10互质的数的个数
1——5中与10互质的数有:1,3 有两个
1——15中与10互质的数有:1,3,7,9,11,13 有6个
根据容斥原理6——15中与10互质的数的个数有 (6+2)-2-2+2 为6个
但是直接判断两个数是否互质十分麻烦。我们换一种方法来判断互质的数的个数
拿样例2作为例子:
1——2中是5的倍数的数不存在 ,也就是0个
1——15中是5倍数的数有 5,10,15 有三个
则是5的倍数的数自然不与5互质 则与5互质的数为
如果以相同的做法求6——15中与10互质的数的个数
我们把10化解成两个质数之积 2*5
在1——5中是2的倍数的有:2,4 有2个
是5的倍数有 :5 一个
在1——15中是2的倍数的有2,4,6,8,10,12,14 有7个数
是5的倍数的有5,10,15 有3个数
但是我们需要注意的是10既是2的倍数页数5的倍数,所以在计算时10这个数只需要减去一次。
所以根据容斥原理
15中是2或5的倍数的个数为 (3+7)-1-1+1 == (3+7)-1 == ==(3+7)-10/(2*5)==9
(X中是Y倍数的个数为X/Y ,比如10中6的倍数为 10/6 为1个)
但根据测试,并不都是减法。
比如求1-30中是2和3和5的倍数
是二的倍数为:2,4,6,8,10,12,14,16,18,20,22,24,26,28,30 总共15个
是三的倍数为:3,6,9,12,15,18,21,24,27,30 总共10个
是五的倍数为:5,10,15,20,25,30 总共6个
则为(10+15+6)-30/(2*3)-30/(2*5)-30/(3*5)+30/(2*5*3) ==31-5-3-2+1==22
所以我们看出当是奇数个质数相乘时,要相加。偶数个质数相乘时要相减。
那么我们要如何枚举组合呢
比如2和3
3和5
5和2
2和3和5
把1--8 (2^质数个数)(不包含8)的所有数转化为2进制
1==> 001
2 ==> 010
3==> 011
4==> 100
5==> 101
6==> 110
7==> 111
1代表用,0代表不用。那么5就代表用2和5,6代表用2和3, 7代表用2和3和5
这样我们就可以很好地枚举所有的质数组合
那么我们贴代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define M(a,b) memset(a,b,sizeof(a))
const int MAXN = 1e3+5;
LL A,B,N;
LL len;
int Case;
LL prime[MAXN];
void deal(LL N)///所有数都能分解为若干质数的乘积(定理)
{
for(LL i =2;i*i<=N;i++){
if(N!=0 && N%i==0) prime[len++] = i;
while(N!=0 && N%i==0) N/=i;
}
if(N>1)prime[len++]=N;
}
LL rc(LL num,LL len)
{
LL ans,temp,len2;
ans = temp = len2 = 0;
for(LL i =1;i<(1<<len);i++){///枚举范围
temp = 1;len2 = 0;///len2用来记录枚举质数的个数
for(LL j=0; j<=len; j++){
if(i & (1<<j)){len2++; temp*=prime[j];}///枚举质数组合情况
}
if(len2&1){///奇加偶减
ans += num/temp;
}
else {
ans -= num/temp;
}
}
return ans;
}
int main()
{
int T; cin>>T;
Case=0;
while(T--){
M(prime,0);
len = 0;
scanf("%lld %lld %lld",&A,&B,&N);
deal(N);
printf("Case #%d: %lld\n",Case++,(B-rc(B,len)-(A-1-rc(A-1,len))));
}
return 0;
}