hdu 4135 Co-prime(分解質因數+容斥定理)
【題目】
Co-primeTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 8210 Accepted Submission(s): 3274Problem 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);
}
}