dutianchen1
2024-11-19 18:45:25
刚刚学完 Raney 引理,写道例题和题解帮助理解。
前置知识:Raney 引理,卡特兰数。
首先我们需要知道,什么样的牌堆不会断抽会赢。
我们定义每张牌的牌效为:打出这张牌后,手中卡牌数量的变化量。
那么特殊牌的卡效为
我们把所有牌的牌效都按顺序存入
定义:
我们不断抽的条件显然就是
并且
而 Raney 引理:
设整数序列
\{A_{i}\} ,\sum A_{i} =1 有且仅有一个整数
x ,满足对A_{x},A_{x+1},A_{x+2}\dots A_{1},A_{2},\dots A_{x-1} 求前缀和s_{i} ,使得\forall s_{i} >0 。
不幸的是,我们会发现原题中
但是我们可以发现,对这个序列任意求前缀和必定为非负,等价于求后缀和必定为负数。
证明:
又因为
那么我们把整个序列取反,再翻转。我们就可以发现现在的序列
根据引理,每个圆排列都只会对答案有一个贡献,而我们需要保证
答案数就是
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const ll mod = 998244353;
inline ll read(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
ll n,m;
ll w[N];
ll qpow(ll x,ll b){
ll res=1;
while(b){
if(b&1) res=res*x%mod;
x=x*x%mod;
b>>=1;
}
return res;
}
int main(){
n=read();
for(int i=1;i<=n;i++)w[i]=read(),m+=w[i];
ll ans=1;
for(int i=2;i<=m;i++)ans=ans*i%mod;
cout<<ans*qpow(m-n+1,mod-2)%mod<<'\n';
return 0;
}