【HDOJ7080】Pty hates prime numbers(容斥原理)
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
- 点赞
- 收藏
- 关注作者
评论(0)