容斥原理
HDU 1796
这道题的题意是说给你一个集合,总共有15个元素,每个元素大小小于等于20;问从1至n的数中,能整除集合中任意一个数的总的个数为多少?
那么根据容斥原理,我们知道,答案为整除一个元素的数个数之和,减去同时整除两个元素的整数个数之和;加上同时整除三个元素的整数个数之和等等。。。这个枚举直接写一个dfs就行了。可以参考一下我的代码,写的比较简洁。
#include <iostream> #include <cstring> #include <cstdio> #include <vector> using namespace std; typedef long long LL; LL n, m; int a[15]; LL ans, step; bool vis[25]; LL gcd(LL a, LL b) { while(b) { LL temp = b; b = a%b; a = temp; } return a; } LL lcm(LL a, LL b) { return a/gcd(a, b)*b; } void dfs(LL cur, int index, int need) { if( need == 0 ) { step += (LL)(n-1)/(LL)cur; return ; } if( m-index+1 < need ) return ; for(int i=index; i<=m; i++) { vis[i] = true; dfs(lcm(cur, a[i]), i+1, need-1); vis[i] = false; } } LL solve() { ans = 0; memset(vis, 0, sizeof(vis)); int dir = 1; for(int i=1; i<=m; i++) { step = 0; dfs(1, 1, i); ans += dir*step; dir *= -1; } return ans; } int main() { memset(vis, false, sizeof(vis)); while( cin>>n>>m ) { for(int i=1; i<=m; i++) { int temp; scanf("%d", &temp); vis[temp] = true;; } m = 0; for(int i=1; i<=20; i++) { if(vis[i]) a[++m] = i; } LL ans = solve(); cout<<ans<<endl; } return 0; }
HDU 4451
这道题是12年金华赛区现场赛的一道水题。可以用容斥原理来做,也可以用巧妙的方法进行枚举。这里简单说一下用容斥原理的做法吧。
所有的穿法为n*m*k,剪掉所有包含一个不和谐搭配的方案数,加上两个都为不和谐的搭配方案数,这样子容斥下来就是最后的结果了。
可以看一下代码,比较简单。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int MAX = 1010; int clothes[MAX], pants[MAX]; int main() { int n, m, k; while(scanf("%d%d%d", &n, &m, &k) != EOF) { if(n == 0 && m == 0 && k == 0) break; memset(clothes, 0, sizeof(clothes)); memset(pants, 0, sizeof(pants)); int p; scanf("%d", &p); int a, b; char s1[10], s2[10]; while(p--) { scanf("%s%d%s%d", s1, &a, s2, &b); if(strcmp(s1, "clothes") == 0) clothes[b]++; else pants[a]++; } int ans = 0; ans = n*m*k; for(int i=1; i<=m; i++) { ans -= (clothes[i]*k); ans -= (pants[i]*n); } for(int i=1; i<=m; i++) ans += clothes[i]*pants[i]; printf("%d\n", ans); } return 0; }