UVA 11806-Cheerleaders

这里写图片描述
这里写图片描述
题目链接

题目解析

题意

在m*n的矩形网格中放k个相同的石子,每个格子最多放一个石子,所有石子都必须用完,保证第一行,第一列,最后一行,最后一列都要有石子,求有多少种方法。
输入数据的组数T,每组数据包含行数M,列数N,石子数K。
输出满足题意的方法种数。

思路

运用容斥原理。全集为S,第一行没有石子的方案集为A,最后一行没有石子的方案集为B,第一列没有石子的方案集为C,最后一列没有石子的方案集为D。所求答案就是在S中,但不在A,B,C,D任何一个集合中的元素个数sum。
sum=C(m*n,k)-(A+B+C+D)+(AB+AC+AD+BC+BD+CD)-(ABC+ABD+BCD)+(ABCD)。
在程序中,用二进制表示A,B,C,D的所有搭配(S对应于空搭配),如果在集合A和B中减去一行;如果在集合C和D中减去一列。最后剩了r行c列,方法数就是C(r*c,k)。

代码
#include<stdio.h>
#include<string.h>
using namespace std;
#define mod 1000007
#define MAXD 500
int c[MAXD+10][MAXD+10];
int main(){
    memset(c,0,sizeof(c));
    c[0][0]=1;
    for(int i=0;i<=MAXD;i++){
        c[i][0]=c[i][i]=1;//初始化边界 
        for(int j=1;j<i;j++)//j<i由c[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 s=0;s<16;s++){//共有16种搭配方式(0~15,二进制1111) 
            int b=0,r=n,a=m;//b统计集合(二进制中1)的个数,奇减偶加 
            if(s&1){
                r--;
                b++;
            }
            if(s&2){
                r--;
                b++;
            }
            if(s&4){
                a--;
                b++;
            }
            if(s&8){
                a--;
                b++;
            }
            if(b&1)//奇减偶加
                sum=(sum+mod-c[r*a][k])%mod;//取余的时候若有减法,加一个模,避免出现负数 
            else
                sum=(sum+c[r*a][k])%mod;
        }
        printf("Case %d: %d\n",cas,sum);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值