美文网首页
Cheerleaders

Cheerleaders

作者: Gitfan | 来源:发表于2017-03-28 19:51 被阅读0次

http://www.cnblogs.com/khbcsu/p/4245943.html
https://vjudge.net/problem/UVA-11806
本题大致意思是讲:给定一个广场,把它分为M行N列的正方形小框。现在给定有K个拉拉队员,每一个拉拉队员需要站在小框内进行表演。但是表演过程中有如下要求:
(1)每一个小框只能站立一个拉拉队员;
(2)广场的第一行,最后一行,第一列,最后一列都至少站有一个拉拉队员;
(3)站在广场的四个角落的拉拉队员可以认为是同时占据了一行和一列。


2.思路分析:
本题如果直接枚举的话难度很大并且会无从下手。那么我们是否可以采取逆向思考的方法来解决问题呢?我们可以用总的情况把不符合要求的减掉就行了。
首先我们如果不考虑任何约束条件,我们可以得出如下结论:

下载我们假定第一行不站拉拉队员的所有的站立方法有A种。最后一行不站拉拉队员的所有的方法有B种。第一列不站拉拉队员的所有的站立方法有C种。最后一列不站拉拉队员的站立方法有D种。
下面我们可以得出最后结果:

下面问题来了我们如何利用代码实现容斥原理呢?我们可以借用离散数学的最大项和最小项知识结合与运算来判断每一项的特征。比如说,含A的和1进行与运算。含B的与2进行与运算。含C的和4进行与运算。含D的和8进行与运算。
然后对于每一种状态,我们利用数字0-15来代替。
在进行这些工作之前,我们还要进行基础性工作,数据初始化和打表。
对于如何打表,我们可以采取组合数公式的递推式进行。打表过程中一定要注意边界问题的处理,要不极容易出错。
#include<stdio.h>
#include<algorithm>
#include <string.h>
using namespace std;
#define maxn 500
typedef long long LL;
int c[maxn+10][maxn+10];
const int mod =1000007;
int main()
{
    memset(c,0,sizeof(c));
    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 t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        int n,m,k,sum=0;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<16;i++)
        {
            int r=n,w=m,b=0;
            if(i&1) {r--;b++;}
            if(i&2) {r--;b++;}
            if(i&4) {w--;b++;}
            if(i&8) {w--;b++;}
            if(b&1) sum=(sum-c[r*w][k]+mod)%mod;
            else sum=(sum+c[r*w][k])%mod;
        }
        printf("Case %d: %d\n",cas,sum);
    }
}

相关文章

  • Cheerleaders

    http://www.cnblogs.com/khbcsu/p/4245943.htmlhttps://vjudg...

网友评论

      本文标题:Cheerleaders

      本文链接:https://www.haomeiwen.com/subject/gmksottx.html