1. 程式人生 > >hdu 4135 Co-prime(分解質因數+容斥定理)

hdu 4135 Co-prime(分解質因數+容斥定理)

【題目】

Co-prime

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

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

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}.

【題意】

給定 t 組資料,給定區間 [a,b] 和 k,輸出區間 [a,b] 中與 k 互質的數的個數。

【思路】

首先,把問題轉化成[1,b]中與k互質的個數-[1,a]中與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)。

【程式碼】

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define Pi acos(-1)
#define eps 1e-8
using namespace std;
typedef long long int ll;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
ll fac[1005],num,ansa,ansb,a,b,k;
void init()
{
    ansa=0,ansb=0,num=0;
    scanf("%lld%lld%lld",&a,&b,&k);
    a--;
    for(ll i=2;i*i<=k;i++)
    {
        if(k%i==0) fac[num++]=i;
        while(k%i==0) k/=i;
    }
    if(k>1) fac[num++]=k;
}
ll gcd(ll a, ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a, ll b){return a*b/gcd(a, b);}
void dfs(ll pre,ll now,ll step)
{
    if(step>num) return;
    ll Lcm=lcm(now,fac[pre]);
    if(step&1)
    {
        ansa+=a/Lcm;
        ansb+=b/Lcm;
    }
    else
    {
        ansa-=a/Lcm;
        ansb-=b/Lcm;
    }
    for(ll i=pre+1;i<num;i++)
        dfs(i,Lcm,step+1);
}
main()
{
    int t; scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        init();
        for(int j=0;j<num;j++)
            dfs(j,fac[j],1);
        ll ans=(b-a)-(ansb-ansa);
        printf("Case #%d: %lld\n",i,ans);
    }
}