给定一个整数 <span id="MathJax-Span-2" class="mrow"><span id="MathJax-Span-3" class="mi">n 和 <span id="MathJax-Span-5" class="mrow"><span id="MathJax-Span-6" class="mi">m 个不同的质数p1,p2,…,pm。
请你求出1∼n 中能被 <span id="MathJax-Span-28" class="mrow"><span id="MathJax-Span-29" class="msubsup"><span id="MathJax-Span-30" class="mi">p1,p2,…,pm 中的至少一个数整除的整数有多少个。
输入格式
第一行包含整数 n 和 m。
第二行包含 m 个质数。
输出格式
输出一个整数,表示满足条件的整数的个数。
数据范围
<span id="MathJax-Span-52" class="mrow"><span id="MathJax-Span-53" class="mn">1≤m≤16,
<span id="MathJax-Span-59" class="mrow"><span id="MathJax-Span-60" class="mn">1≤n,pi≤109
输入样例:
10 2
2 3
输出样例:
7
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 20;
int p[N], n, m;
int main() { cin >> n >> m;
for(int i = 0; i < m; i++) cin >> p[i];
int res = 0;
//枚举从1 到 1111...(m个1)的每一个集合状态, (至少选中一个集合)
for(int i = 1; i < 1 << m; i++) {
int t = 1; //选中集合对应质数的乘积
int s = 0; //选中的集合数量
//枚举当前状态的每一位
for(int j = 0; j < m; j++){
//选中一个集合
if(i >> j & 1){
//乘积大于n, 则n/t = 0, 跳出这轮循环
if((LL)t * p[j] > n){ t = -1; break; }
s++; //有一个1,集合数量+1
t *= p[j];
}
}
if(t == -1) continue;
if(s & 1) res+= n/t; //选中奇数个集合,则系数应该是1, n/t为当前这种状态的集合数量
else res -= n / t; //反之则为 -1
}
cout << res << endl;
return 0;
}
标签:int,res,质数,容斥,整数,选中,集合,原理,整除
From: https://www.cnblogs.com/liyuzhong/p/17615002.html