【HDOJ7080】Pty hates prime numbers(容斥原理)

举报
小哈里 发表于 2022/05/10 22:53:09 2022/05/10
【摘要】 problem Pty hates prime numbers Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K ...

problem

Pty hates prime numbers
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 293 Accepted Submission(s): 87

Problem Description
Pty thinks prime numbers are extremely annoying numbers. Specifically, he hates the first k prime numbers.

As ”Hate me Hate my dog.” , if one prime factor of the integer x is what Pty hates, Pty will also hate x.

Now Pty wants to know how many integers in [1,n] he dosen’t hate.

Formally, Pty wants to know ∑nx=1[∀i∈[1,k],p[i]∤x] (p[i] means the ith prime number) .

Input
The first line contains a single integer T(1 ≤ T ≤ 100000) — the number of test cases

The only line of each test case contains two integers n,k(1 ≤ n ≤ 1018,1 ≤ k ≤ 16).

Output
For each test case, output the number of integers Pty doesn’t hate.

Sample Input
5
10 1
20 2
30 3
40 4
50 5

Sample Output
5
7
8
9
11

Source
2021“MINIEYE杯”中国大学生算法设计超级联赛(10)

Recommend
IceyWang | We have carefully selected several similar problems for you: 7099 7098 7097 7096 7095

solution

题意:

  • 给出n和k,求1-n中有多少个数不是前k个素数中的任意一个的倍数。
  • n <=1e18, k <= 16,T<=1e5

思路:

  • 不难想到容斥原理,二进制枚举,设枚举的乘积为x,去考虑前k个质数是否选择, 答案为 a n s + = n / x ∗ ( − 1 ) 形 成 x 质 数 的 个 数 ans+= n/x∗(−1)^{形成x质数的个数} ans+=n/x(1)x。 复杂度2^k,会超时。
  • 考虑优化,假设k==8,发现前8个素数的乘积为9699690,注意到如果数x不是前八个素数的倍数的话,那么x%9699690也不是前八个素数的倍数,所以我们可以预处理出1-9699690的答案,对于超过的部分让其==([n/9699690] + n%9699690)进行处理。
    在这里插入图片描述
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL m = 9699690;//2∗3∗5∗7∗11∗13∗17∗19
LL p[20] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

vector<LL>a[18], b[18];//a,b表示前k个素数中选择偶数/奇数个能形成的数
void dfs(int x, LL y, int z, int k){
    if(x>k){
        if(z==1)a[k].push_back(y);//由偶数个素数组成
        else b[k].push_back(y);
        return ;
    }
    dfs(x+1, y,z,k);       //不使用第x个素数
    dfs(x+1,y*p[x], -z, k);//使用第x个素数
}
LL sum[m+10], as;
void init(){
    for(int k = 1; k <= 16; k++){//暴力前k个素数所能形成的乘积值
        if(k<=8)dfs(1,1,1,k);
        else dfs(9,1,1,k);
    }
    for(int i = 1; i <= 8; i++){ //标记1-m中可以被前8个数整除的数
        for(int j = p[i]; j <= m; j+=p[i]){
            sum[j] = 1;
        }
    }
    for(int i = 1; i <= m; i++){ //维护sum[i]表示1-i中不能被前8个数整除的数的个数
        sum[i] = sum[i-1]+(sum[i]==0);
    }
    as = sum[m];  //as表示1-9699690中不能被前8个数整除的数
}

int main(){
    init();
    int T;  cin>>T;
    while(T--){
        LL n, k;  cin>>n>>k;
        LL ans = 0;
        if(k <= 8){
            for(LL x : a[k])ans += n/x;
            for(LL x : b[k])ans -= n/x;
        }else{
            LL t;
            for(LL x : a[k])t=n/x, ans += (t/m)*as+sum[t%m];
            for(LL x : b[k])t=n/x, ans -= (t/m)*as+sum[t%m];
        }
        cout<<ans<<"\n";
    }
    return 0;
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

文章来源: gwj1314.blog.csdn.net,作者:小哈里,版权归原作者所有,如需转载,请联系作者。

原文链接:gwj1314.blog.csdn.net/article/details/119859162

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。