「AGC021E」Ball Eat Chameleons 题解
本文网址:https://www.cnblogs.com/zsc985246/p/17501300.html ,转载请注明出处。
传送门
题目翻译
有 \(n\) 只变色龙,一开始都是蓝色。
你会依次扔出 \(k\) 个球,每次扔出都要指定一只变色龙吃掉这个球。扔出的球可以是红色或蓝色。
变色龙从蓝色变成红色当且仅当它吃的红球比蓝球多,从红色变成蓝色当且仅当它吃的蓝球比红球多。
求最后能使所有变色龙都变成红色的方案数,对 \(998244353\) 取模。
两个方案不同当且仅当至少一次喂的球颜色不同。
思路
注意到,一条变色龙最终为红色只有两种情况:
-
吃的红球比蓝球多。
-
吃的红球和蓝球一样多,但吃的最后一个球是蓝球。
所以我们尝试分情况考虑。
我们设扔出的红球个数为 \(R\),蓝球个数为 \(B\),其中 \(R+B=k\)。
-
\(R < B\)
此时必定有变色龙吃的蓝球比红球多,所以一定无解。
-
\(R \ge B + n\)
让除第一条外的变色龙都只吃一个红球,那么剩下的球满足 \(R' > B'\),全部丢给第一条变色龙就可以了,所以一定有解。答案为 \(C_{R+B}^{R}\)。
-
\(B \le R < B + n\)
-
\(R = B\)
此时只能让每条变色龙都吃相同数量的红球和蓝球。
那么显然,合法方案的最后一个球一定为蓝球。
所以其实可以等价于长度为 \(n-1\),满足 \(R'=R,B'=B-1\) 的合法方案数。
这样我们就将 \(R=B\) 转化为了 \(B < R < B + n\) 的情况。
-
\(B < R < B + n\)
我们有多出来的 \(R-B\) 个红球,所以我们可以让 \(R-B\) 条变色龙吃的红球比蓝球多。我们称这些变色龙为 \(\text{I}\) 类变色龙。
我们还剩下 \(n-(R-B)\) 条 \(\text{II}\) 类变色龙。我们可以如果可以选出这么多对红球+蓝球 的组合,分给每条 \(\text{II}\) 类变色龙,然后将剩下的球全部给一条 \(\text{I}\) 类变色龙就可以满足条件。
但如果我们无法选出足够多对红球+蓝球 ,那么显然一定会有 \(\text{II}\) 类变色龙无法变成红色,所以一定无解。
综上可知,如果我们可以选出 \(n-(R-B)\) 对红球+蓝球 的组合,则有解,否则一定无解。
这其实与卡特兰数的模型很像。我们当前在 \((0,0)\),向右表示红球,向上表示蓝球,目标点是 \((R,B)\),而我们不能走到直线 \(y=x+B-(n-(R-B))=x+R-n\) 的严格上方。
那么我们通过组合数得到答案为 \(C_{R+B}^{R}-C_{R+B}^{2R-n+1}\)。
-
然后我们只需要枚举 \(R\),通过组合数计算答案。
代码实现
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=2e6+10;
using namespace std;
const ll p=998244353;
//组合数模板
ll ksm(ll a,ll b){ll bns=1;while(b){if(b&1)bns=bns*a%p;a=a*a%p;b>>=1;}return bns;}
ll jc[N],inv[N];
void init_C(ll n){jc[0]=jc[1]=1;For(i,2,n)jc[i]=jc[i-1]*i%p;inv[n]=ksm(jc[n],p-2);Rep(i,n-1,0)inv[i]=inv[i+1]*(i+1)%p;}
ll C(ll n,ll m){if(n<m)return 0;/*记得特判*/return jc[n]*inv[m]%p*inv[n-m]%p;}
int main(){
ll n,k;
scanf("%lld%lld",&n,&k);
if(k<n){
printf("0");
return 0;
}
init_C(2*k);//组合数预处理
ll ans=0;
For(R,1,k){
ll B=k-R;
if(R<B)continue;
if(R==B)B--;
//R>=B+n也可以用这个公式,因为R-n>=B,所以2*R-n+1>=R+B+1,即后面的组合数返回0
ans=(ans+C(R+B,R)-C(R+B,2*R-n+1)+p)%p;
}
printf("%lld",ans);
return 0;
}
尾声
如果你发现了问题,你可以直接回复这篇题解
如果你有更好的想法,也可以直接回复!