HDU 4135-Co-prime(容斥求区间内与N互质的个数(队列||位运算))
2015-08-24 18:25
330 查看
题目地址:HDU 4135
题意:求[A,B]区间内与N互质的数的个数。
思路:我们可以用容斥计算出[1,B]之间和[1,A-1]之间的与N互质的数,然后相减即可。然后我们用一种快速的方法求出[1,X]之间的与N互质的数,首先我们求出N的质因子,[1,X]之间与N的质因子成倍数关系的数肯定与N不成互质关系。
Eg:X=12,N=30 ,N的质因子为2,3,5。
(2,4,6,8,10)->X/2 6个;
(3,6,9,12)->X/3 4个;
(5,10)->X/5 ;
然后根据容斥原理X/2+X/3+X/5-X/(2*3)-X/(2*5)-X/(3*5)+X/(2*3*5)。
方法一:
方法二:
对于X=12,N=30来说,N的质因子为2,3,5。如果用”0”,”1”标记2,3,5。为”1”时需要,为”0”时不需要,那么,二进制数010,011,······,111,刚好对应上式中的2,3,5在除数中出现的情况。
题意:求[A,B]区间内与N互质的数的个数。
思路:我们可以用容斥计算出[1,B]之间和[1,A-1]之间的与N互质的数,然后相减即可。然后我们用一种快速的方法求出[1,X]之间的与N互质的数,首先我们求出N的质因子,[1,X]之间与N的质因子成倍数关系的数肯定与N不成互质关系。
Eg:X=12,N=30 ,N的质因子为2,3,5。
(2,4,6,8,10)->X/2 6个;
(3,6,9,12)->X/3 4个;
(5,10)->X/5 ;
然后根据容斥原理X/2+X/3+X/5-X/(2*3)-X/(2*5)-X/(3*5)+X/(2*3*5)。
方法一:
#include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <sstream> #include <algorithm> #include <set> #include <queue> #include <stack> #include <map> #include <bitset> using namespace std; typedef __int64 LL; const int inf=0x3f3f3f3f; const double pi= acos(-1.0); const double esp=1e-6; using namespace std; const int Maxn=2*1e5+10; LL prime[Maxn]; LL sprime[Maxn]; bitset<Maxn>pri; LL k,cnt; void is_prime() { pri.set(); for(LL i=2; i<Maxn; i++) { if(pri[i]) { prime[k++]=i; for(LL j=i+i; j<Maxn; j+=i) pri[j]=0; } } } void Divide(LL n)//分解质因子 { cnt=0; LL t=(LL)sqrt(1.0*n); for(LL i=0; prime[i]<=t; i++) { if(n%prime[i]==0) { sprime[cnt++]=prime[i]; while(n%prime[i]==0) n/=prime[i]; } } if(n>1) sprime[cnt++]=n; } LL Ex(LL n)//容斥原理之队列实现 { LL q[Maxn]; LL sum=0; LL t=1; q[0]=-1; for(LL i=0; i<cnt; i++) { LL x=t; for(LL j=0; j<x; j++){ q[t]=q[j]*sprime[i]*(-1); t++; } } for(LL i=1; i<t; i++) sum+=n/q[i]; return sum; } int main() { int T; int icase=1; LL A,B,N; LL res; is_prime(); scanf("%d",&T); while(T--) { scanf("%I64d %I64d %I64d",&A,&B,&N); Divide(N); res=(B-Ex(B))-(A-1-Ex(A-1)); printf("Case #%d: ",icase++); printf("%I64d\n",res); } return 0; }
方法二:
对于X=12,N=30来说,N的质因子为2,3,5。如果用”0”,”1”标记2,3,5。为”1”时需要,为”0”时不需要,那么,二进制数010,011,······,111,刚好对应上式中的2,3,5在除数中出现的情况。
#include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <sstream> #include <algorithm> #include <set> #include <queue> #include <stack> #include <map> #include <bitset> using namespace std; typedef __int64 LL; const int inf=0x3f3f3f3f; const double pi= acos(-1.0); const double esp=1e-6; using namespace std; const int Maxn=1e5+10; LL prime[Maxn]; LL sprime[Maxn]; bitset<Maxn>pri; LL k,cnt; void is_prime() { pri.set(); for(LL i=2; i<Maxn; i++) { if(pri[i]) { prime[k++]=i; for(LL j=i+i; j<Maxn; j+=i) pri[j]=0; } } } void Divide(LL n)//分解质因子 { cnt=0; LL t=(LL)sqrt(1.0*n); for(LL i=0; prime[i]<=t; i++) { if(n%prime[i]==0) { sprime[cnt++]=prime[i]; while(n%prime[i]==0) n/=prime[i]; } } if(n>1) sprime[cnt++]=n; } /* 1<<n是将1向前推动n位,例如n=5,那么1<<5=100000,i<(1<<5)的话就是在[00001,11111]中选择 i&j是只有对应位都为1的时候才是1,例如101和001的结果为001. */ LL Ex(LL n) { LL ans=0; LL tmp,flag; LL i,j; for(i=1;i<(LL)(1<<cnt);i++) { tmp=1; flag=0; for(j=0;j<cnt;j++) if(i&((LL)(1<<j))){//这个就可以代表用了第几个 flag++; tmp*=sprime[j]; } if(flag&1) ans+=n/tmp; else ans-=n/tmp; } return ans; } int main() { int T; int icase=1; LL A,B,N; LL res; is_prime(); scanf("%d",&T); while(T--) { scanf("%I64d %I64d %I64d",&A,&B,&N); Divide(N); res=(B-Ex(B))-(A-1-Ex(A-1)); printf("Case #%d: ",icase++); printf("%I64d\n",res); } return 0; }
相关文章推荐
- Palindrome Number
- linux c/c++ 后台开发基础之:c++日志模块
- The Dole Queue(UVA 133)
- ZOJ 3435 Ideal Puzzle Bobble (莫比乌斯反演基础题)
- 范式的数据库具体解释
- php - mysql数据表的内容管理
- UVALive 5987
- java通过rJava调用R失败的问题总结
- 1090. Highest Price in Supply Chain (25) -计层的BFS改进
- CocoaPods安装和使用及问题:Setting up CocoaPods master repo
- Java 文件分块上传客户端源代码
- 1090. Highest Price in Supply Chain (25) -计层的BFS改进
- hdu 4302 Holedox Eating(优先队列/线段树)
- 最简单的HTML5游戏——贪吃蛇
- Java实现堆
- STL学习----入门(1)[unordered_map]
- AC+DP练习
- 运行hadoop程序遇到的一些问题及解决方案
- linux bash总结(二) 高级部分(适合初学者学习和非初学者参考)
- IOS7导航条与状态栏的那些事儿