Description
有 n n 个人打球,分成四种,个人没有球拍没有球, b b 个人只有球拍没有球,个人只有球没有球拍, d d 个人既有球拍也有球,问从这个人中选出若干使得没有两只球拍一个球的方案数
Input
第一行一整数 T T 表示用例组数,每组用例输入四个整数
(1≤T≤103,0≤a,b,c,d≤107,a+b+c+d≥1) ( 1 ≤ T ≤ 10 3 , 0 ≤ a , b , c , d ≤ 10 7 , a + b + c + d ≥ 1 )
Output
输出方案数,结果模 998244353 998244353
Sample Input
3
1 1 1 1
2 2 2 2
3 4 5 6
Sample Output
12
84
2904
Solution
考虑不合法方案,即凑够两个球拍一个球,分三种情况:
1.从 d d 个人中至少选两个,那么前个人随便选,方案数 (2d−d−1)⋅2a+b+c ( 2 d − d − 1 ) ⋅ 2 a + b + c
2.从 d d 个人中选一个,那么要从个人中至少选一个,其他人随便选,方案数 d⋅(2b−1)⋅2a+c d ⋅ ( 2 b − 1 ) ⋅ 2 a + c
3. d d 个人不选,个人中至少选两个, c c 个人中至少选一个,方案数
Code
#include<cstdio>
using namespace std;
typedef long long ll;
#define mod 998244353
int T,a,b,c,d;
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int Pow(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)ans=mul(ans,x);
x=mul(x,x);
y>>=1;
}
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
int ans=Pow(2,a+b+c+d);
int t=mul(Pow(2,a),mul(add(Pow(2,b),mod-b-1),add(Pow(2,c),mod-1)));
ans=add(ans,mod-t);
t=mul(d,mul(mul(add(Pow(2,b),mod-1),Pow(2,a)),Pow(2,c)));
ans=add(ans,mod-t);
t=mul(add(Pow(2,d),mod-d-1),Pow(2,a+b+c));
ans=add(ans,mod-t);
printf("%d\n",ans);
}
return 0;
}