给定一个整数 n和 m个不同的质数 p1,p2,…,pm。
请你求出 1∼n中能被 p1,p2,…,pm中的至少一个数整除的整数有多少个。
输入格式
第一行包含整数 n和 m。
第二行包含 m个质数。
输出格式
输出一个整数,表示满足条件的整数的个数。
数据范围
1≤m≤16,
1≤n,pi≤10^9
输入样例:
1. 10 2 2. 2 3
输出样例:
7
容斥原理定义:在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
思路:用遍历模运算在数据量小的时候是常用的算法,但是本题n为10^9,复杂度过高会TLE。
这里使用容斥原理,不计算出每个符合情况的数有哪些,仅去计算个数有多少,这样就降低了时间复杂度。
p[N]存放质数,假设pi指可以被p[i]整除的个数,那么pi=n/p[i];
类推pi并上pj pi||pj=n/pi*pj;利用容斥原理就可以计算出p1p2p3....pn的个数,qie时间复杂度为2^m
#include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int N=16; int n,m,p[N]; ll res; int main(){ cin>>n>>m; for(int i=0;i<m;i++)cin>>p[i]; for(int i=1;i<1<<m;i++) { int t=1,cnt=0; for(int j=0;j<m;j++) { if(i>>j&1) { cnt++; if((ll)t*p[j]>n) { t=-1; break; } t*=p[j]; } } if(t!=-1) { if(cnt%2)res+=n/t; else res-=n/t; } } cout<<res<<endl; return 0; }