HDU 4135 Co-prime(容斥原理 + 基础数论)

来源:互联网 发布:unity3d项目实战教程 编辑:程序博客网 时间:2024/06/05 23:49

传送门

Co-prime

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


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

Source
题目大意:给一个区间 [a,b] 求这个区间中 与 n 互素的个数。解题思路:这个问题可以转化为求 [1,b] 区间中与 n 互素的个数 ans1 减去 [1,a1] 区间中与 n 互素的个数 ans2 ,那么 [1,x] 区间中与 n 互素的个数怎么求呢,可以先将 n 进行素因子分解,然后用区间 x 除以 素因子,就得到了与 n 的 约数是那个素因子的个数,然后每次这样求一遍,但是发现有重复的:举个例子 [1,10] 区间中与 6 互素的个数,应该是 10(10/2+10/3) 但是这样多减去了他们的最小公倍数 6 的情况,所以在加上 10/6 也就是:

10(10/2+10/310/6)=3

这就用到了容斥原理,知道了这个,题目也就可以做了,先进行素因子分解,然后二进制枚举子集

进行容斥原理(奇加偶减):

My Code

/**2016 - 08 - 08 上午Author: ITAKMotto:今日的我要超越昨日的我,明日的我要胜过今日的我,以创作出更好的代码为目标,不断地超越自己。**/#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <vector>#include <queue>#include <algorithm>#include <set>using namespace std;typedef long long LL;typedef unsigned long long ULL;const int INF = 1e9+5;const int MAXN = 1e6+5;const int MOD = 1e9+7;const double eps = 1e-7;const double PI = acos(-1);using namespace std;bool prime[MAXN];LL p[MAXN];int k;///素数筛选void isprime(){    k = 0;    memset(prime, 0, sizeof(prime));    for(LL i=2; i<MAXN; i++)    {        if(!prime[i])        {            p[k++] = i;            for(LL j=i*i; j<MAXN; j+=i)                prime[j] = 1;        }    }}LL fac[MAXN/100];int cnt = 0;void Dec(LL x){    cnt = 0;    for(int i=0; p[i]*p[i]<=x&&i<k; i++)    {        if(x%p[i]==0)        {            fac[cnt++] = p[i];            while(x%p[i]==0)                x /= p[i];        }    }    if(x > 1)        fac[cnt++] = x;}LL Solve(LL x){    LL ret = 0;    for(LL i=1; i<(1LL<<cnt); i++)    {        int sum = 0, tmp = 1;        for(int j=0; j<cnt; j++)        {            if(i & (1LL<<j))            {                sum++;                tmp *= fac[j];            }        }        if(sum & 1)            ret += x/tmp;        else            ret -= x/tmp;    }    return ret;}int main(){    isprime();    int T;    LL N, A, B;    scanf("%d",&T);    for(int cas=1; cas<=T; cas++)    {        scanf("%I64d%I64d%I64d",&A,&B,&N);        Dec(N);        printf("Case #%d: %I64d\n",cas,B-Solve(B)-A+1+Solve(A-1));    }    return 0;}
0 0