Ball Eat Chameleons[AGC021]

链接

AtCoder

luogu

题解

设选了 $R$ 个红球,则选了 $B=k-R$ 个蓝球。

考虑一只变色龙最后是红色的当且仅当:

  1. 所吃红球>蓝球;
  2. 所吃红球=蓝球,且最后一次吃的是蓝球。

接下来来看什么时候可行。

分类讨论:

  1. $R<B$,此时方案数显然为 $0$。因为至少存在一只变色龙是蓝色。

  2. $R\geq B+n$,此时方案数显然为 $\binom{R+B}{B}$,因为每只变色龙都可以符合第一种情况。

  3. $R=B$,这时候必须满足序列中最后一个是蓝球,否则必然不合法,然后转换成 $(R,B-1)$ 的问题。

  4. $R\in (B,B+n)$,这时候需要有 $n-(R-B)$ 只变色龙符合第二种情况。并且,当这只变色龙吃的球的个数大于 $2$ 的话,可以将最后的一个红球和蓝球不吃,让给剩下 $R-B$ 只满足第一种情况的变色龙吃,也能满足情况。

    因此,这种情况就变成了给定一个 R,B 序列,里面有 $R$ 个 R,$B$ 个 B,至少要找到 $n-(R-B)$ 个互不相交的子序列,且这个子序列是 RB,问符合情况的方案数。

    R 看成 $+1$,B 看成 $-1$,上面的条件相当于:

    对于每个前缀都满足前缀和 $\geq B-(n-(R-B))=R-n$

    这时候由经典的折线法容斥一下就好了,得到方案数:$\binom{R+B}{R}-\binom{R+B}{2R-n+1}$。

预处理组合数,时间复杂度 $O(k)$。

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const ll mod=998244353;
inline ll Add(ll x,ll y){x+=y; return (x<mod)?x:x-mod;}
inline ll Dec(ll x,ll y){x-=y; return (x<0)?x+mod:x;}
inline ll Mul(ll x,ll y){return x*y%mod;}
inline ll Pow(ll x,ll y)
{
y%=(mod-1);ll ans=1;for(;y;y>>=1,x=x*x%mod)if(y&1) ans=ans*x%mod;
return ans;
}
const int N=5e5+5;
ll fac[N],inv[N];
int n,k,R,B;
inline ll C(int n,int m)
{
if(n<0||m<0||n-m<0) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void init(int n)
{
fac[0]=1; fo(i,1,n) fac[i]=fac[i-1]*i%mod;
inv[n]=Pow(fac[n],mod-2); fd(i,n,1) inv[i-1]=inv[i]*i%mod;
}
ll ans;
int main()
{
cin>>n>>k;
if(n>k) return puts("0")&0;
init(k);
fo(R,0,k)
{
B=k-R;
if(R<B) continue;
if(R>=B+n) {ans=Add(ans,C(R+B,R)); continue;}
if(R==B) B--;
ans=Add(ans,Dec(C(R+B,R),C(R+B,2*R-n+1)));
}
printf("%lld",ans);
return 0;
}