题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6425
题意:总共有n=a+b+c+d个人,其中a个人什么都没有,b个人有一个球拍,c个人有一个球,d个人有一个球与一个球拍。现要组织比赛,n个人每个人都可以参加或者不参加,那么总共的情况有2^n种,问2^n种方案中有多少种不符合要求。
解析:由于没有球和没有球拍都是不合法的,首先思路是用没有球方案数加上没有球拍方案数,然后容斥减掉既没有求有没有求球拍的情况。
注意:对于球来说,0个球是不合法的;对于球拍来说0个或1个球拍都是不合法的;
答案首先加上以下3项:
- ①.0个球的方案数为:2^(n-(c+d));即:手上有球的c+d个人都没来,而其余的n-(c+d)个人随意组合。
- ②.0个球拍方案数为:2^(n-(b+d));即:手上有球拍的b+d个人都没来,而其余的n-(b+d)个人随意组合。
- ③.1个球拍方案数为:(b+d)*2^(n-(b+d));考虑b类型和d类型的人中来了1个,其余n-(b+d)个人随意组合。
再减去以下2项重复的:
- ④.0个球0个球拍的方案数:2^(n-(c+b+d));
- ⑤.0个球1个球拍的方案数:b*2^(n-(c+b+d));即:b类型的人来了一个,c和d类型的人一个都没来,a类型任意来。
公式到此结束,但别扭的是,一个球一个拍也是不合法的,但是容斥的时候并没有体现这一情况。这是因,这里在加的时候我们在③将此种情况只算了一次,所以不用在容斥减的时候再减一遍。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
const ll mod=998244353;ll a,b,c,d;ll pow_mod(ll n,ll k,ll mod)//快速幂求n^k余m的结果
{ll res=1;n=n%mod;while(k>0){if(k&1)res=res*n%mod;n=n*n%mod;k>>=1;}return res;
}int main()
{int T;scanf("%d",&T);while(T--){scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&d);ll n=a+b+c+d;ll ans=pow_mod(2,n-(c+d),mod); //+①ans=(ans+(b+d+1)*pow_mod(2,n-(b+d),mod)%mod)%mod;//+②+③ans=(ans-(b+1)*pow_mod(2,n-(c+b+d),mod)%mod+mod)%mod;//-④-⑤printf("%I64d\n",ans);}return 0;
}