原题: URAL 1091 http://acm.timus.ru/problem.aspx?space=1&num=1091
题意:要求找出K个不同的数字使他们有一个大于1的公约数,且所有的数字都不能大于一个指定的数字S。
解法:可以考虑每个S内的素数,此素数和它的所有倍数构成一个集合,则可以在这些集合中任意去k个元素,C(n,k)即为这种情况下的方法种数,比如K = 3,S = 10,
则可以形成3个集合: {2,4,6,8,10} , {3,6,9}, {5,10} ,第一个集合C(5,3),第二个集合C(3,3),第三个集合为0,同时可以看到,6在两个集合中出现了,所以要减去一个6的情况,这样就是容斥原理了。
枚举一个素数,两个素数即可,因为如果三个素数的话,公倍数至少为2x3x5 = 30, 此时S内是30的倍数只有一个(S<=50),就是30本身,此时要选K>=2个是不可能的。所以三个及以上可以不计。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define ll long long using namespace std; #define N 10007 ll C[55][55]; int prime[10] = {2,3,5,7,11,13,17,19,23}; void calc_C() { memset(C,0,sizeof(C)); C[1][0] = C[1][1] = 1; for(int i=2;i<=51;i++) { C[i][0] = 1; for(int j=1;j<=51;j++) C[i][j] = C[i-1][j] + C[i-1][j-1]; } } int main() { int k,S,i,j,res,num,flag; calc_C(); while(scanf("%d%d",&k,&S)!=EOF) { ll res = 0; flag = 9; for(i=0;i<9;i++) { num = S/prime[i]; if(num < k) { flag = i; break; } else res += C[num][k]; } for(i=0;i<flag;i++) { for(j=i+1;j<flag;j++) { num = S/(prime[i]*prime[j]); if(num < k) break; else res -= C[num][k]; } } printf("%lld\n",min((ll)10000,res)); } return 0; }
2014 Super Training #3 H Tmutarakan Exams --容斥原理,布布扣,bubuko.com
时间: 2024-10-08 09:48:15