AGC021E Ball Eat Chameleons
Link
一只变色龙变成红色的要么是吃的红球比蓝球多,要么是吃的红球和蓝球一样多且最后一吃的是蓝球。
设总共有\(R\)个红球和\(B\)个蓝球,若\(R<B\)则显然无解;若\(R=B\)则最后一个球一定是蓝球,其方案数等于\(R\)个红球与\(B-1\)个蓝球时的方案数。因此我们只需要考虑\(R>B\)的情况。
若\(R-B\ge n\),那么我们可以让所有变色龙吃的红球都比蓝球多,因此任何一个序列都是合法的,方案数为\({R+B\choose R}\)。
若\(R-B<n\),那么\(n−R+B\)只变色龙吃的红球和蓝球一样多,\(R−B\)只变色龙吃的红球比蓝球多一个(若存在合法方案,那么一定存在一个上述形式的合法方案,可以用调整法证明)。
让吃的红球和蓝球一样多的变色龙都只吃一个红球和一个蓝球,剩下来的球不管以什么顺序吃都是合法的了。不难发现这是最优的构造方案。
也就是说序列合法的充要条件是能够取出\(n-R+B\)对不交的RB
子序列。
这等价于对任意一个前缀而言,蓝球比红球多不超过\(R-n\)个。
转化为格路计数问题即可,方案数为\({R+B\choose R}-{R+B\choose 2R-n+1}\)。
#include<cstdio>
const int N=500007,P=998244353;
int fac[N],ifac[N];
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int mod(int x){return x+(x>>31&P);}
int pow(int a,int b){int r=1;for(;b;b>>=1,a=1ll*a*a%P)if(b&1)r=1ll*a*r%P;return r;}
int C(int n,int m){return n<m||m<0? 0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
int main()
{
int n,k,ans=0;scanf("%d%d",&n,&k);
for(int i=fac[0]=1;i<=k;++i) fac[i]=1ll*fac[i-1]*i%P;
ifac[k]=pow(fac[k],P-2);for(int i=k;i;--i) ifac[i-1]=1ll*ifac[i]*i%P;
for(int i=0,f;i+i<=k&&i+n<=k;++i) f=(i+i==k),inc(ans,mod(C(k-f,i-f)-C(k-f,i+i+n-k-1-f)));
printf("%d",ans);
}