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

来源:互联网 发布:js输入框输入触发事件 编辑:程序博客网 时间:2024/05/17 09:37

题意:求区间 [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++;}}


0 0
原创粉丝点击