AcWing 890. 能被整除的数

题目传送门

题目描述

给定一个整数 nn 和 mm 个不同的质数 p1,p2,…,pmp1,p2,…,pm。

请你求出 1∼n1∼n 中能被 p1,p2,…,pmp1,p2,…,pm 中的至少一个数整除的整数有多少个。

输入格式

第一行包含整数 nn 和 mm。

第二行包含 mm 个质数。

输出格式

输出一个整数,表示满足条件的整数的个数。

数据范围

1≤m≤161≤m≤16,
1≤n,pi≤1091≤n,pi≤109

输入样例:

10 2
2 3

输出样例:

7

算法求解

分析

这个题目是容斥原理的公式

p[i]表示读入的质数

\(S_i\) 表示在1--n内能被 p[i]整除的数的集合


https://www.acwing.com/solution/content/29702/

代码

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
const int N = 20;
int p[N];
int n, m;

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 0; i < m; i++) scanf("%d", &p[i]);
	
	LL res = 0;
	for(int i = 1; i < 1 << m; i++)
	{
		int cnt = 0;
		int t = 1;
		for(int j = 0; j < m; j++)
		{
			
			// 如果选中了这个集合 
			if((i >> j) & 1)
			{
				if((LL)t*p[j] > n)
				{
					t = -1;
					break;	
				} 
				
				cnt++;
				t *= p[j];  // 能被选中集合的交集整除的是该集合内质数的乘积 
			}
			if(t == -1) continue;
			
			if(cnt & 1) res += n/t;
			else		res -= n/t;
		}
	}
	
	cout << res << endl;
	return 0;

	/* 暴力 
	scanf("%d%d", &n, &m);
	
	for(int i = 0; i < m; i++)
	 	scanf("%d", &a[i]);
	
	int res = 0;
	for(int i = 1; i <= n; i++)
	{
		for(int j = 0; j < m; j++)
			if(i % a[j] == 0)
			{
				res ++;
				break;
			} 
	}
	
	cout << res << endl;
	return 0;*/
} 

时间复杂度

\(O(2^m * m)\)

参考文章

https://www.acwing.com/solution/content/29702/

posted @ 2022-03-05 10:36  VanHope  阅读(54)  评论(0编辑  收藏  举报