容斥原理(位运算)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
long long prime[50005],num[50005];
long long temp[50005];
long long get(long long n,long long cur){
        long long i,j,k,sum,sign,sumsum;
        sumsum=0;
        for(i=1;i<(1<<cur);i++){
            j=i;k=sign=0;sum=1;
            while(j){                    //二进制法生成所有子集
                if(j&1){                 //详见:http://blog.csdn.net/stay_accept/article/details/47204619
                sum*=temp[k];
                sign++;
                }
                j>>=1;k++;
            }
            if(sign%2)                  //容斥原理,奇加偶减
            sumsum+=(n/sum);
            else
            sumsum-=(n/sum);
        }
        return sumsum;
}
int main(){
    long long t,i,j,k,a,b,n,cur;
    memset(prime,0,sizeof(prime));
    k=0;
    for(i=2;i<=50000;i++){                 //素数筛防止超时,数据小不用也可以
        if(!prime[i])
        num[k++]=i;
        for(j=0;j<k&&num[j]*i<=50000;j++){
            prime[num[j]*i]=1;
            if(i%num[j]==0)
            break;
        }
    }
    cin>>t;
    for(k=1;k<=t;k++){
        cin>>a>>b>>n;
        cur=0;
        for(i=0;num[i]*num[i]<=n;i++){
            if(n%num[i]==0){
                temp[cur++]=num[i];           //分解素因子
                while(n%num[i]==0)
                n/=num[i];
            }
        }
        if(n>1)temp[cur++]=n;
        printf("Case #%lld: %lld\n",k,(b-get(b,cur))-(a-1-get(a-1,cur)));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zyy_1998/article/details/81185314