!HDU 4135 Co-prime-容斥原理-(位运算技巧)

题意:求区间 [a~b]内与n互素的数的个数

分析:

容斥原理很容易想到,关键在于怎么实现。

有三种方法:dfs、队列数组、位运算。我觉得位运算比较好理解。先求出n的质因数设有cnt个,则这cnt个数有2^cnt-1种组合。用二进制位很容易证明:设有三个质因数作为例子,则 001,010,100,011,101,110,111,就分别表示了选一个,选两个,选三个的各种情况,这样就很明显了,共有 2^3-1 也就是 7 种,所以我们可以用某一位是否为1来判断是否选择这个质因数。那么问题又来了,如何用位来实现呢,这里就用到了位运算技巧:预算符 & 就可以判断某一位是否为1。上面已经证明组合有2^cnt-1种,也就是情况要讨论这么多次,所以我们就在每种情况下用运算符 & 判断是否这种情况的时候选择了这个质因数。若选择了那么计数器加1,且把这个数乘进去。具体看代码

另外,容斥原理有一篇不错的文章,先mark:http://www.cppblog.com/vici/archive/2011/09/05/155103.html

代码:

#include<iostream>
using namespace std;
int t;
long long a,b,n;
long long prim[1000010];
long long s1,s2;
int cnt;
void init() //求n的质因数,用的是上一篇博文的方法一
{
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			prim[cnt++]=i;
			while(n%i==0){
				n/=i;
			}
		}
	}
	if(n>1) prim[cnt++]=n;
}
long long work(long long m)
{
	long long sum=0;
	for(int i=1;i<(1<<cnt);i++){
		int mul=1;
		int tot=0;
		for(int j=0;j<cnt;j++){
			if(i&(1<<j)){   //位运算判断当前情况是否选择了这个质因数,若不理解手动试一试
				tot++;
				mul*=prim[j];
			}
		}
		if(tot&1) sum+=m/mul;
		else sum-=m/mul;
	}
	return sum;
}
int main()
{
	cin>>t;
	int cas=1;
	while(t--){
		cin>>a>>b>>n;
		cnt=0;
        init();
        s1=work(a-1);
        s2=work(b);
        cout<<"Case #"<<cas<<": ";
        cout<<b-a+1-(s2-s1)<<endl;
        cas++;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值