给定一个整数 n� 和 m� 个不同的质数 p1,p2,…,pm�1,�2,…,��。
请你求出 1∼n1∼� 中能被 p1,p2,…,pm�1,�2,…,�� 中的至少一个数整除的整数有多少个。
输入格式
第一行包含整数 n� 和 m�。
第二行包含 m� 个质数。
输出格式
输出一个整数,表示满足条件的整数的个数。
数据范围
1≤m≤161≤�≤16,
1≤n,pi≤1091≤�,��≤109
输入样例:
10 2
2 3
输出样例:
7
思路:
求1-n能被整除p整除的个数,让n/p下取整。
我们可以设Si集合中元素的个数为-n能被整除pi整除的个数,根据容斥原理,答案即为s1+s2+...-(s1∩s2)-(s2∩s3)+.....。(可以搜一下容斥原理公式)。
我们可以用二进制枚举从1-(1<<m)-1,每个数都对应着一种集合情况。
注:
我开始用深搜写,发现同一种情况会被枚举多次(顺序不同,即为排列数),而二进制枚举是组合,同一种情况只会计数一次。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define LL long long
#define N 10000
#define rep(i,a,b) for (int i = a; i <= b; i++)
#define per(i, a, b) for(int i=a;i>=b;i--)
LL p[20],sum;
LL n,m;
bool vis[20];
void seek()
{
for(LL i=1;i<=(1<<m)-1;i++)
{
LL k = 1,cn=0,t=1;
rep(j, 0, m - 1)
{
if ((i >> j) & 1)
{
if (k * p[j] > n)
{
t = -1;
break;
}
k *= p[j];
cn++;
}
}
if (t != -1)
{
if (cn % 2 == 1)
sum += n / k;
else
sum -= n / k;
}
}
}
int main()
{
cin>> n >> m;
rep(i, 0, m - 1)
cin >> p[i];
seek();
cout << sum << endl;
return 0;
}
文章介绍了一种计算在给定整数范围内能被特定质数整除的整数个数的方法,涉及容斥原理和二进制编码优化。
1186

被折叠的 条评论
为什么被折叠?



