Cheerleaders UVA

来源:互联网 发布:强力卸载软件 编辑:程序博客网 时间:2024/05/17 02:43

题述:对于一个n*m的广场,共有n*m个格子,要放k个东西,每个格子上只能放一个东西且第一行、最后一行、第一列和最后一列上都必须至少放一个东西。在四个顶点的格子相当于同时占了一行和一列。

思路:训练赛的时候第一反应是也许可以枚举所有的情况,但稍微一想发现那是不现实的,就转去做其他题目了,结果一个dfs因为姿势不对tle到无奈,所以最后没时间写这道题。赛后仔细想了想,又结合网上的文字叙述自己推了一遍。这道题情况太多故只能考虑他的相反情况,最后用所有放法减去他的所有相反情况。相反情况就是第一行或最后一行或第一列或最后一列上不能放东西,说到或应该很容易想到得用容斥原理,分别用0 1 2 3代表第一行不放、第一列不放、最后一行不放、最后一列不放,四个元素可以用0~16枚举其所有情况,0000代表四个都放,1111代表四个都不放。容斥原理是加上奇数个减去偶数个,这里是要减去这些相反情况,故是减去奇数个,加上偶数个。

代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<sstream>#include<deque>#include<stack>#include<set>#include<map>using namespace std;typedef long long ll;typedef unsigned long long ull;const double eps = 1e-6;const int maxn = 400 + 5;const int mod = 1000007;const int dx[] = {1, -1, 0, 0, -1, -1, 1, 1};const int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};const int Dis[] = {-1, 1, -5, 5};const double inf = 0x3f3f3f3f;int n, m, k;ll c[maxn][maxn];void init(){    c[0][0] = 1;    for(int i = 1; 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(){    init();    int t, kase = 0;    scanf("%d", &t);    while(t--){        scanf("%d%d%d", &n, &m, &k);        vector<int> vec;        ll ans = c[n * m][k];        for(int i = 0; i < 16; ++i){            vec.clear();            for(int j = 0; j < 4; ++j){                if(i & (1 << j)) vec.push_back(j);//将0 1 2 3中不能放东西的加到集合中。            }            int len = vec.size();            ll tmp = 0;            if(len == 1){                if(vec[0] & 1) tmp = c[n * m - n][k];                else tmp = c[n * m - m][k];            }            else if(len == 2){                if((vec[0] & 1) && (vec[1] & 1)) tmp = c[n * (m - 2)][k];                else if(!(vec[0] & 1) && !(vec[1] & 1)) tmp = c[(n - 2) * m][k];                else tmp = c[(n - 1) * (m - 1)][k];            }            else if(len == 3){                if((vec[0] + vec[1] + vec[2]) & 1) tmp = c[(n - 2) * (m - 1)][k];                else tmp = c[(n - 1) * (m - 2)][k];            }            else if(len == 4){                tmp = c[(n - 2) * (m - 2)][k];            }            if(len & 1) ans = (ans - tmp + mod) % mod;            else ans = (ans + tmp) % mod;        }        printf("Case %d: %lld\n", ++kase, ans);    }    return 0;}



原创粉丝点击