您的位置:首页 > 其它

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)。

方法一:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: