HDU 4135 Co-prime【容斥原理】【质因数分解】

Co-prime

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6704    Accepted Submission(s): 2653


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 <= 10 15) and (1 <=N <= 10 9).
 

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
 
  
21 10 23 15 5
 
Sample Output
 
  
Case #1: 5Case #2: 10
Hint
In the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.
 

Source
 

Recommend
lcy


题意:

找出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互质的数为

(1-15中的数 减去 1-15中是五的倍数的数)-(1-2中的数 减去 1-2中是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;
}


猜你喜欢

转载自blog.csdn.net/qq_37405320/article/details/80229937
今日推荐