杭电4135 Co-prime(容斥原理第一题)

Co-prime

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


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
/*
题目大意:求1--n中与m互质的个数
终于搞定了,之前搞懂,又看了好长时间,
Time:2014-8-19 19:27
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=100000+10;
__int64 pri[MAX];
__int64 GetPrime(__int64 x,__int64 N){
	int k=0;
	memset(pri,0,sizeof(pri));
	for(__int64 i=2;i*i<=N;i++){//对N进行质因数分解 
		if(N%i==0){
			pri[k++]=i;
			while(N%i==0)N/=i; 
		}
	}
	if(N>1)pri[k++]=N;//因为N本身可能是素数 
	__int64 sum=0,val,num;
	for(__int64 i=1;i<(1<<k);i++){//此处相当于利用2进制来表示状态比如6 110 表示取第一个和第二个素数 2 3 
		val=1;num=0;
		for(int j=0;j<k;j++)if(i&(1<<j)){//应该j=0 。。半天找不着错。。。无语 
			val*=pri[j];
			num++;
		}
		if(num&1){//奇加偶减是容斥原理 
			sum+=x/val;
			//如果val不是质数,x/val则表示与 它 的公因子 都互质的个数 
			// 如果是质数  x/val代表 1-x中 与 val不互质的个数 ,
			//r(i)是某个质因子 N/r(i)所求 区间 1--N与 r(i)不互质的个数 
			//比如 1--8中与 6 不互质的个数为 1-8中为 8/2+8/3-8/(2*3)
			//由容斥原理 奇加偶减 便可求得 
		}else{
			sum-=x/val;
		}
	}
	return x-sum; 
}
void solve(){
	int T;
	int d=0; 
	scanf("%d",&T);
	while(T--){
		__int64 a,b,N;
		scanf("%I64d%I64d%I64d",&a,&b,&N);
		__int64 ans=GetPrime(b,N)-GetPrime(a-1,N);
		printf("Case #%d: %I64d\n",++d,ans);
	}
}
int main(){
	solve();
return 0;
}
/*
AC
Time:2014-12-18 12:47 更新
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX=100000+10;
LL pri[MAX];
int Get_prime(LL n){
    LL temp=n,k=0;
    for(int i=2;i*i<=n;i++){
        if(temp%i==0){
            pri[k++]=i;
            while(temp%i==0){
                temp/=i;
            }
        }
    }
    if(temp>1)pri[k++]=temp;//本身是素数

    return k;
}
LL Get_ans(LL x,int k){
    int maxn=1<<k;
    LL ans=0;
    for(LL i=1;i<maxn;i++){
            LL temp=1;int num=0;
        for(int j=0;j<k;j++){
            if(i&(1<<j)){
                temp*=pri[j];
                num++;
            }
        }
        if(num&1)//不用考虑大于a的情况
            ans+=x/temp;
        else
            ans-=x/temp;
    }
    return x-ans;
}
int main(){
    int T,nCase=1;
    LL a,b,n;
    scanf("%d",&T);
    while(T--){
            memset(pri,0,sizeof(pri));
        scanf("%lld%lld%lld",&a,&b,&n);
        int k=Get_prime(n);
        LL ans=Get_ans(b,k)-Get_ans(a-1,k);
        printf("Case #%d: ",nCase++);
        printf("%lld\n",ans);
    }
return 0;
}

//超时代码。。。就是分解质因数i*i就是15ms,,时间差好大。。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX=10000+10;
LL pri[MAX];
int Get_prime(LL n){
    int k=0;
    for(int i=2;i<=n;i++){//这儿没有写成i*i<=n就超时。。。
        if(n%i==0){
            pri[k++]=i;
            while(n%i==0){
                n/=i;
            }
        }
    }
    if(n!=1)pri[k++]=n;

    return k;
}
LL Get_ans(LL x,int k){
    int maxn=1<<k;
    LL ans=0;
    for(LL i=1;i<maxn;i++){
            LL temp=1;int num=0;
        for(int j=0;j<k;j++){
            if(i&(1<<j)){
                temp*=pri[j];
                num++;
            }
        }
        if(num&1)//不用考虑大于a的情况
            ans+=x/temp;
        else
            ans-=x/temp;
    }
    return x-ans;
}
int main(){
    int T,nCase=1;
    LL a,b,n;
    scanf("%d",&T);
    while(T--){
            memset(pri,0,sizeof(pri));
        scanf("%lld%lld%lld",&a,&b,&n);
        int k=Get_prime(n);
        LL ans=Get_ans(b,k)-Get_ans(a-1,k);
        printf("Case #%d: ",nCase++);
        printf("%lld\n",ans);
    }
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值