1. 程式人生 > 其它 >AcWing 890. 能被整除的數

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/