hdu 4135(容斥原理)

来源:互联网 发布:java迷宫小游戏设计 编辑:程序博客网 时间:2024/06/13 10:36

Co-prime

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


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
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
The Third Lebanese Collegiate Programming Contest
题意:给定a、b、c,求a到b区间内与c互质的数。(小范围可以欧拉函数,大范围直接容斥)
思路:题意其实就是用(1,b)区间与n互质的数的个数减去(1,a-1)区间与n互质的数的个数,转化为了(1,m)与n互质个数。
首先看数据范围肯定是不能正着暴力求解的,那么反过来想一下就可以求不与n互素的个数,也就是说和n有相同的素因子。
考虑n的所有素因子num[i],求区间内能任意整除num[i]的,然后直接总数减去这些,然后就光荣的错了,因为a到b中可能有一些数是几个素因子构成的,比如6=2*3,如果你n的素因子里面也含有2和3,那么你就会减去2次,也就是多减了。所以就上容斥了,关于容斥我上篇文章已经详细介绍。采用二进制位压缩法,用二进制的0,1来表示二进制第几个质因子是否被取到,1表示取到,0表示没取到, 如果有奇数个1,就相加,反之则相减。状态总数就是2^m,用欧拉函数处理出这个数的所有质因子。
如果还没看懂的话,去看这位的解释:http://www.cnblogs.com/jiangjing/archive/2013/06/03/3115470.html
AC代码:
#include<bits/stdc++.h>using namespace std;typedef long long LL;const int maxn=1e6+5;LL num[maxn];LL n,cnt;LL a,b;void prime(LL n){    cnt=0;    for(LL i=2;i*i<=n;i++)    {        if(n&&n%i==0)        {            while(n%i==0)            {                n/=i;            }            num[cnt++]=i;        }    }    if(n>1) num[cnt++]=n;}LL ans(LL n,LL m){    LL res=0;    LL y=(LL)1<<m;    for(LL i=1;i<y;i++)    {        int flag=0;        LL tem=1;        for(LL j=0;j<m;j++)        {            if(i&(LL)(1<<j))//这里是判断目前第几个因子被用到。            {                flag++;//因子个数                tem*=num[j];            }        }        if(flag&1) res+=n/tem;        else res-=n/tem;    }    return res;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%I64d%I64d%I64d",&a,&b,&n);        static int t=1;        prime(n);        LL sum=b-ans(b,cnt)-(a-1-ans(a-1,cnt));        printf("Case #%d: %lld\n",t++,sum);    }}
递归版本:
#include<bits/stdc++.h>using namespace std;const int maxn=1e6+5;typedef long long LL;LL prime[maxn],a,b,n,cnt;void Init(LL n){    cnt=0;    for(LL i=2;i*i<=n;i++)    {        if(n%i==0)        {            while(n%i==0)            {                n/=i;            }            prime[cnt++]=i;        }    }    if(n>1) prime[cnt++]=n;}LL dfs(LL pos,LL num){    LL ans=0;    for(LL i=pos;i<cnt;i++)    {        LL tem=num/prime[i];        ans+=tem-dfs(i+1,tem);    }    return ans;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%lld%lld%lld",&a,&b,&n);        Init(n);        LL sum=(b-dfs(0,b))-(a-1-dfs(0,a-1));        static int t=1;        printf("Case #%d: %lld\n",t++,sum);    }    return 0;}

原创粉丝点击