hdu 4135 Co-prime(容斥定理入門)

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

2
1 10 2
3 15 5

Sample Output

Case #1: 5
Case #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}.
解題思路:求區間[A,B]與N互質的數的個數,咱們能夠從其對立面來考慮:分別求區間[1,A-1]、區間[1,B]中與N不互質的數的個數爲num一、num2,那麼區間[A,B]與N互質的數的個數就有(B-num2)-(A-1-num1)。怎麼求出區間[1,X]與N不互質的數的個數呢?先分解出N的全部素因子,而後用這些素因子來篩選計算出區間[1,X]中與N不互質的數的個數即X/p_i(p_i爲素因子,X爲區間右端點),由於任何一個不小於2的數都能表示成若干個素數的乘積,這樣就獲得區間[1,X]中是素因子的倍數的個數,但爲了避免重複和不遺漏計數,應採用容斥定理,公式: ,其中選擇某幾個素因子能夠當作是二進制對應bit上的1,若是當前所選個數爲奇數,符號爲正,不然爲負。注意:容斥計數x/p_i中p_i是幾個素數的最小公倍數,因爲素數之間是互質的,因此能夠直接相乘起來做爲其最小公倍數。
AC代碼:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int t,cnt,prime[15];LL a,b,n;
 5 LL solve(LL x){//求與n不互質的總個數
 6     int num;LL ans=0,tp;
 7     for(int i=1;i<(1<<cnt);++i){//用二進制來表示每一個質因子是否被使用,即有2^cnt-1種可能,此時cnt較小,題目中1e9最多也就8個素因子,二進制優化
 8         tp=1,num=0;
 9         for(int j=0;j<cnt;++j)
10             if(i&(1<<j))num++,tp*=prime[j];//表示選擇哪幾個素因子
11         if(num&1)ans+=x/tp;//奇加
12         else ans-=x/tp;//偶減
13     }
14     return x-ans;
15 }
16 int main(){
17     while(~scanf("%d",&t)){
18         for(int i=1;i<=t;++i){
19             scanf("%lld%lld%lld",&a,&b,&n);cnt=0;
20             for(LL j=2;j*j<=n;++j){//求出n內的全部質因子
21                 if(n%j==0){
22                     prime[cnt++]=j;
23                     while(n%j==0)n/=j;
24                 }
25             }
26             if(n>1)prime[cnt++]=n;
27             printf("Case #%d: %lld\n",i,solve(b)-solve(a-1));//區間差
28         }
29     }
30     return 0;
31 }
相關文章
相關標籤/搜索