南京理工大学第八届程序设计大赛 #C Count_Prime Solution

3 篇文章 0 订阅

Description
给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。
两个数互质当且仅当他们除了1之外没有其他的公共因子或者他们最大的公共因子是1。1和任何数是互素的。 Input 第一行输入一个整数T(1 <= T <= 100),表示T组测试数据。 接下来T行,每行3个整数a,b,n(1 <= a <=b <=10^15, 1<= n <= 10^9),用空格隔开。 Output 输出一个整数表示和n互质的数的个数。
Sample Input

2
1 10 2
3 10 5

Sample Output

5 6

感觉自己讲不清楚,引用一下NJUST comzyh的题解吧,总而言之就是分解+容斥原理

容斥原理、先对n分解质因数,分别记录每个质因数,那么所求区间内与某个质因数不互质的个数就是n/r(i),假设r(i)是r的某个质因子 假设只有三个质因子,总的不互质的个数应该为p1+p2+p3-p1p2-p1p3-p2p3+p1p2*p3, 及容斥原理,pi代表n/r(i),即与某个质因子不互质的数的个数,当有更多个质因子的时候,可以用状态压缩解决,二进制位上是1表示这个质因子被取进去了。如果有奇数个1就相加,反之则相减。

C++ Code
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <bitset>
using namespace std;
const int inf=0x3f3f3f3f;
const double pi= acos(-1.0);
const double esp=1e-6;
const int MAX=2*1e5+10;
long long prime[MAX];
long long sprime[MAX];
bitset<MAX> pri;
long long k,cnt;
void is_prime() {
    pri.set();
    for(long long i=2; i<MAX; i++) {
        if(pri[i]) {
            prime[k++]=i;
            for(long long j=i+i; j<MAX; j+=i)
                pri[j]=0;
        }
    }
}
void Divide(long long n) {
    cnt=0;
    long long t=(long long)sqrt(1.0*n);
    for(long long 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;
}
long long Ex(long long n) {
    long long q[MAX];
    long long sum=0;
    long long t=1;
    q[0]=-1;
    for(long long i=0; i<cnt; i++) {
        long long x=t;
        for(long long j=0; j<x; j++) {
            q[t]=q[j]*sprime[i]*(-1);
            t++;
        }
    }
    for(long long i=1; i<t; i++)
        sum+=n/q[i];
    return sum;
}
int main() {
    int T;
    int icase=1;
    long long A,B,N;
    long long res;
    is_prime();
    cin>>T;
    while(T--) {
        cin>>A>>B>>N;
        Divide(N);
        res=(B-Ex(B))-(A-1-Ex(A-1));
        cout<<res<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值