\(\text{link}\) 。也是一道非常巧妙的 \(\texttt{dp}\) 。
容易想到把括号变成 \(\pm 1\)。考虑括号序列合法等价于前缀和 \(\ge 0\),我们可以想加入 \(()\) 或 \()(\) 对前缀的影响。
设加入的位置的前一位前缀和为 \(x\),则加入 \(()\) 相当于把 \(x\) 替换为 \([x,x+1,x]\),加入 \()(\) 相当于把 \(x\) 替换为 \([x,x-1,x]\)。
则原问题等价于初始给定一个集合 \(S={0}\),有 \(n\) 次操作,每次等概率地选择集合中的一个元素 \(x\),并有 \(p\) 的概率把 \(x,x+1\) 加入 \(S\),有 \(1-p\) 的概率把 \(x,x-1\) 加入 \(S\),求\(n\) 次操作后 \(S\) 中所有元素非负的概率。
显然概率转方案,最终除以 \((2n-1)!!\)。
令 \(f_{n,x}\) 表示进行了 \(n\) 次操作,初始在集合中的数为 \(x\) 的方案数,最终答案就是 \(\dfrac{f_{n,0}}{(2n-1)!!}\)。则
\(f_{n,x}=p\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1-i}\dfrac{(n-1)!}{i!j!(n-1-i-j)!}f_{i,x}f_{j,x+1}f_{n-1-i-j,x}+ (1-p)\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1-i}\dfrac{(n-1)!}{i!j!(n-1-i-j)!}f_{i,x}f_{j,x-1}f_{n-1-i-j,x}\)
解释一下:比如果加入 \(x,x+1\) 是求方案数,我们就枚举新加入的 \(x,x+1\) 在之后基于它们各进行了几次操作,就是枚举 \(i,j\),然后剩下的 \(n-1-i-j\) 次操作就是基于原来在集合中的 \(x\) 操作。
由于顺序不一定要乘上一个系数(就是那里的阶乘)。加号右半边也是同理。
这时复杂度是 \(O(n^4)\) ,不能接受,显然考虑前缀和优化。
我们发现加号左右两边很像啊,于是考虑交换求和顺序,先枚举 \(j\),这时 \(\dfrac{(n-1)!}{i!j!(n-1-i-j)!}\) 我们把它变为 \(\dbinom{n-1}{j}\dbinom{n-1-j}{i}\) 。
则 \(f_{n,x}=\sum\limits_{j=0}^{n-1}\dbinom{n-1}{j}(pf_{j,x+1}+(1-p)f_{j,x-1})\sum\limits_{i=0}^{n-1-i-j}\dbinom{n-1-j}{i}f_{i,x}f_{n-1-i-j,x}\) 。
令 \(g_{n,x}=\sum\limits_{i=0}^{n}\dbinom{n}{i}f_{i,x}f_{n-i,x}\),则 \(f_{n,x}=\sum\limits_{j=0}^{n-1}\dbinom{n-1}{j}(pf_{j,x+1}+(1-p)f_{j,x-1})g_{n-1-j}\) 。
这样复杂度就是 \(O(n^3)\) 了,可以接受。
有一点要注意,就是初始化我们要假设所有 \(f_{0,x}\) 都为 \(1\),因为我们这样 \(\texttt{dp}\) 是假定初始所有数都可能出现。这样所有 \(g_{0,x}=1\) 。
$\texttt{code}$
#include<bits/stdc++.h>
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=505,mod=998244353;
int n,p,P,jc[N],inv[N],f[N][N],g[N][N],s=1;
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
inline int C(int n,int m){return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;}
int main()
{
scanf("%d%d",&n,&p);p=796898467ll*p%mod;P=(mod+1-p)%mod;
jc[0]=1;for(int i=1;i<=n;i++) jc[i]=1ll*jc[i-1]*i%mod;
inv[n]=ksm(jc[n],mod-2);for(int i=n-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
for(int i=0;i<=n;i++) f[0][i]=g[0][i]=1;for(int i=1;i<=n*2;i+=2) s=1ll*s*i%mod;
for(int i=1;i<=n;i++)
for(int j=0;j<=n;j++)//f{i,j}
{
for(int k=0;k<=i-1;k++) f[i][j]=(f[i][j]+(1ll*p*f[k][j+1]+(j>0?1ll*P*f[k][j-1]:0))%mod*C(i-1,k)%mod*g[i-1-k][j])%mod;
for(int k=0;k<=i;k++) g[i][j]=(g[i][j]+1ll*C(i,k)*f[k][j]%mod*f[i-k][j])%mod;
}
printf("%d",1ll*f[n][0]*ksm(s,mod-2)%mod);
return 0;
}
<\details>