算法竞赛入门经典——训练指南

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;
    }
}
View Code

 

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;
    }
}
View Code

 

posted @ 2017-03-25 21:39  Silence、  阅读(1308)  评论(0编辑  收藏  举报