UVa 11806 Cheerleaders 【容斥】

本文探讨了一种使用状态压缩动态规划(状压DP)和容斥原理解决复杂组合计数问题的方法。通过将问题转化为边界无人的情况,利用组合数预处理技巧,有效地解决了边界有人的计数难题。代码实现中运用了状压思想,极大地简化了计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址

A,B,C,D 如果是代表上下左右 边界都有人 的话,
边界 = {A,B,C,D} A,B,C,D 还有相交的部分。
根据容斥原理
那答案就是 A+B+C+D-AB-AC-AD-BC-BD-CD+ABC+ABD+BCD-ABCD
但是计算会很麻烦,,
拿A来说
A=C (m,1) + C (m,2) +。。。。 + C (m,min(m,k));
我们知道那个 组合数求和等于 2的 m次方,
但是 min(m,k)让情况复杂,k=min(m,k)的时候 得不出2的 m次方。
所以转换思路,
令,ABCD代表 上下左右边界没有人。

全集=(边界有人)+(边界没人)

边界有人=全集—边界没人
没人就好做多了,如果算不在上边界就是 从 (行数—1)*列 里面 调 k 个格子。
把组合数提前打表。
而且用到了状压的思想,,(我感叹了半个晚上)
代码依然是是偷来的
原文

#include<iostream>
#define  ll  long long
#define mod 1000007
using namespace std;

int  c[405][405]={0};
void  zuhe()
{
    for(int i=0;i<=404;++i)
    {
        c[i][0]=1;
        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()
{
    zuhe();
  int t,T;
  cin>>t;
  T=t;
  while(t--)
  {
      int sum=0;
      int  m,n,k;
      cin>>n>>m>>k;
      for(int s=0;s<16;++s)
      {
         int  e=m,r=n;
          int ans=0;
          if(s&1)
          {
              r--;
              ans++;
          }
          if(s&2)
            {
               r--;
               ans++;
            }
            if(s&4)
            {
                e--;
                ans++;
            }

            if(s&8)
            {
                e--;
                ans++;
            }
            if( ans&1 )
                sum=(sum +mod- c[r*e][k])%mod;
            else
                sum=(sum + c[r*e][k])%mod;

      }


      cout<<"Case "<<T-t<<": "<<sum<<endl;
  }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值