算法竞赛入门经典——训练指南
1. UVa 11300
我的代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; long long C[1000010], M, a; int main() { int n; while (~scanf("%d", &n)) { C[0] = 0; for (int i = 1; i <= n; i++) { scanf("%lld", &a); C[i] = C[i-1]+a; } M = C[n]/n; for (int i = 1; i < n; i++) C[i] -= i*M; sort(C, C+n); long long ans = 0, x = C[n/2]; for (int i = 0; i < n; i++) ans += abs(x-C[i]); cout<<ans<<endl; } }
2.UVa 11806
题意:在m行n列里放k个相同的石子,每个格子只能放一个,并且第一行、最后一行、第一列、最后一列必须有石子,输出总方案数模1000007的余数(2<=m,n<=20 k<=500)
关键词:容斥原理,集合表示
思路:容斥原理。集合A,B,C,D分别表示“第一行没有石子”、“最后一行没有石子”、“第一列没有石子”、“最后一列没有石子”,全集为S,那么所求答案即为“在S中而不在A,B,C,D中”的元素个数,容斥原理求解。用二进制表示四个集合的16种搭配,若最后剩r行c列,显然方法数为C(rc,k)。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 510; const int mod = 1000007; int C[maxn][maxn]; void init() { memset(C, 0, sizeof(C)); for (int i = 0; i < maxn; i++) { C[i][0] = C[i][i] = 1; for (int j = 1; j < i; j++) C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod; } } int main() { int T, m, n, k; init(); cin>>T; for (int t = 1; t<= T; t++) { int sum = 0; cin>>m>>n>>k; for (int s = 0; s < 16; s++) { ///枚举16种搭配方式 int b = 0, r = m, c = n; ///集合数,行数,列数 if (s&1) r--, b++; ///第一行没石头 if (s&2) r--, b++; ///最后一行没石头 if (s&4) c--, b++; ///第一列没石头 if (s&8) c--, b++; ///最后一列没石头 if (b&1) sum = (sum + mod - C[r*c][k]) % mod; ///奇数个条件做减法 else sum = (sum + C[r*c][k]) % mod; ///偶数个条件做加法 } cout<<"Case "<<t<<": "<<sum<<endl; } }