题目链接:
http://acm.hdu.edu.cn/showproblem.php?
题目大意:
给你一个整数N。和M个整数的集合{A1、A2、…、Am}。集合内元素为非负数(包括零),求小于N的
正整数(1~N-1)中,能被M个整数的集合中随意一个元素整除的正整数个数。
比如N = 12。M = {2,3},在1~N-1中,能被2整除的数为{2,4,6。8。10},能被3整除的数为
{3。6,9}。则所求集合为{2,3,4。6,8,9,10},共7个,则答案为7。
思路:
就是求M个集合的并集。先看上边的样例。能被2整除的数集合S1为{2,4,6,8。10},能被3整除的数
集合S2为{3,6。9}。而两者交集S12为能被LCM(2,3) = 6整除的数为{6}。
则两者并集 S = S1 + S2 - S12。
依据容斥定理得:若有M个数,则可求出1~N-1中能被不同组合的公倍数整除的个数。
1~N-1能被公倍数整除的个数为 (N-1) / LCM。然后依据奇数项加,偶数项减的原则得出答案个数。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<string> using namespace std; int Gcd(int a,int b) { if(a < b) int temp = a, a = b, b = temp; if(b == 0) return a; return Gcd(b,a%b); } int Lcm(int a,int b) { return a/Gcd(a,b)*b; } int N,M; int A[220],Select[220]; int Solve() { int ans = 0; for(int i = 1; i < (1 << M); ++i) { int odd = 0; for(int j = 0; j < M; ++j) { if((1<<j) & i) { Select[++odd] = j; } } int LCM = 1; for(int j = 1; j <= odd; ++j) LCM = Lcm(LCM,A[Select[j]]); if(odd & 1) ans += N/LCM; else ans -= N/LCM; } return ans; } int main() { int d; while(~scanf("%d%d",&N,&M)) { for(int i = 0; i < M; ++i) { scanf("%d",&d); if(d) A[i] = d; else i--,M--; } N--; printf("%d\n",Solve()); } return 0; }