给定一个整数 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;
}