「AGC021E」Ball Eat Chameleons
「AGC021E」Ball Eat Chameleons
考虑如何判定一个合法的颜色序列。
不妨设颜色序列中有 \(R\) 个红球,\(B\) 个蓝球,所以有 \(R+B=k\)。
考虑分情况讨论:
-
\(R<B\)
显然无解。
-
\(R\ge B\)
-
\(R\ge B+n\)
显然任意一种序列都合法,因为对于任意一个白球,无论你给一条变色龙分配多少个蓝球,你总能分配更多的红球给这条变色龙,使其变为红色。
直接计算即可。
-
$ B\le R < B+n$
-
\(R=B\)
此时对于每一个蓝球,都只有唯一的一个红球与之对应。也就是说,对于某只变色龙,蓝球一定要比红球后分配,否则这只变色龙一定仍然为蓝色。
根据这一点,我们可以知道此时合法的颜色序列的最后一个球的颜色一定是蓝色。
然后,我们就可以转化为长度为 \(n-1\) 的子序列,且 \(R^{\prime}=R,B^{\prime}=B-1\) 的子问题。
-
\(R>B\)
实际上我们只需要考虑这种情况的问题。
这意味着有 \(R-B\) 只变色龙只用吃一个红球,而对于其他的 \(n-(R-B)\) 条变色龙,他们需要吃等量的红球和蓝球,且需要保证他们最后吃的那个球一定是蓝色。
那么考虑一种最坏情况就是,对于这些要吃红蓝球的变色龙,他们每条龙都差一个就吃满了所有的蓝球,然后这时候吃完所有的红球,再把最后一个蓝球补齐。
也就是说,\(\max\{B-R\}=B-(n-(R-B))=R-n\)。
我们可以把问题抽象为每次可以移动一个单位向量 \((0,1)\) 或 \((1,0)\),问从 \((0,0)\) 到 \((R,B)\) 的合法路径数。
那么问题就变成了不经过 \(y=x+(R-n)\) 的路径的方案数。
根据翻折的性质,答案就等于所有的方案数到减掉将终点关于直线对称后的新终点的方案数。
即
\[\binom {R+B}{R}-\binom{R+B}{2R-n+1} \]
-
-
枚举 \(R\) 计算即可。
时间复杂度为 \(O(k)\)。
/*---Author:HenryHuang---*/
/*---Never Settle---*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=2e6+5;
const ll p=998244353;
ll ksm(ll a,ll b,ll p){
ll ans=1;
while(b){
if(b&1) ans=1ll*ans*a%p;
b>>=1,a=1ll*a*a%p;
}
return ans;
}
ll inv[maxn],fac[maxn];
ll C(ll n,ll m){
if(n<m) return 0;
return 1ll*fac[n]*inv[m]%p*inv[n-m]%p;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
ll n,k;cin>>n>>k;
if(k<n) cout<<0<<'\n',exit(0);
fac[0]=inv[0]=1;
for(ll i=1;i<=2*k;++i){
fac[i]=1ll*fac[i-1]*i%p;
}
inv[2*k]=ksm(fac[2*k],p-2,p);
for(ll i=2*k-1;i>=1;--i) inv[i]=1ll*(i+1)*inv[i+1]%p;
ll ans=0;
for(ll r=1;r<=k;++r){
ll b=k-r;
if(r<b) continue;
if(r==b) --b;
ans=1ll*(ans+1ll*(C(r+b,r)-C(r+b,2*r-n+1)+p)%p)%p;
}
cout<<ans<<'\n';
return 0;
}