易知一只变色龙最后是红色,当且仅当他吃的红球比蓝球多或红蓝数目相等且最后一个是蓝球(至少吃一个红球)。
考虑如何判定一个方案是否合法。显然一个合法的方案红球数目不小于蓝球,不妨设红球比蓝球多
p
p
p个(
p
≥
0
p\geq 0
p≥0),那么红球有
K
+
p
2
\frac{K+p}{2}
2K+p个,蓝球有
K
−
p
2
\frac{K-p}{2}
2K−p个,这里要求红球数目至少是
N
N
N。
显然当
p
≥
N
p\geq N
p≥N时一定有解。否则当
p
>
0
p>0
p>0时,我们如果能找出
N
−
p
N-p
N−p个不相交的红蓝球的对,使得每个对都是红球在前面一定有解,这显然是一个充要条件(不要的球可以丢给某只红球数目多的变色龙)。这个条件不太好做,不过它其实等价于不存在某个前缀中蓝减红大于
K
+
p
2
−
N
\frac{K+p}{2}-N
2K+p−N,转化后的问题容易用翻折线的思想解决,算几个组合数即可。
有一个特殊情况是
p
=
0
p=0
p=0时,多的球不能丢个某只变色龙,于是最后一个球需要是蓝球,特殊处理即可。
时间复杂度
O
(
N
+
K
)
\mathcal O(N+K)
O(N+K)。
#include <bits/stdc++.h>
#define MOD 998244353
using namespace std;
typedef long long ll;
ll pow_mod(ll x,int k) {
ll ans=1;
while (k) {
if (k&1) ans=ans*x%MOD;
x=x*x%MOD;
k>>=1;
}
return ans;
}
ll facd[500005],facv[500005];
void pre(int n) {
facd[0]=1;
for(int i=1;i<=n;i++) facd[i]=facd[i-1]*i%MOD;
facv[n]=pow_mod(facd[n],MOD-2);
for(int i=n-1;i>=0;i--) facv[i]=facv[i+1]*(i+1)%MOD;
}
inline ll C(int n,int m) {
return (n<m)?0:facd[n]*facv[m]%MOD*facv[n-m]%MOD;
}
int main() {
int n,k;
scanf("%d%d",&n,&k);
pre(k);
int ans=0;
if (!(k&1)&&(k>>1)>=n) {
ans=(ans+C(k-1,k>>1))%MOD;
ans=(ans-C(k-1,k-n+1)+MOD)%MOD;
}
for(int i=1;i<=k;i++)
if (!((i^k)&1)&&((k+i)>>1)>=n) {
ans=(ans+C(k,(k+i)>>1))%MOD;
if (i<n) ans=(ans-C(k,k+i-n+1)+MOD)%MOD;
}
printf("%d\n",ans);
return 0;
}