一道题
题目
其中
分析
直接统计概率是不好做的,直接计算全部操作完合法括号串有多少个也不好做。因为操作包含两部分:选择位置与选择类型,选择类型的概率可以直接在
一般的括号区间计数dp为设状态
回到此题,可以套路的将
发现这样设计在状态合并时有很好的性质,因为最终的和为
因此可列出转移方程式。
复杂度是
观察发现长度一样的串本质上是一致的,令
可知
代码
void Main(){
n=rd;
int x=rd,y=rd;
p=x*qmi(y,mod-2)%mod;
C[0][0]=dp[0][0][0]=1;
for(int i=1;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
for(int i=0;i<=n;i++)
sum[0][i][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=n;j++){
int x=0,y=0;
for(int k=1;k<i;k++){
x=sum[k][j][0]*((sum[i-k][j][1]+sum[i-k][j][0])%mod)%mod;
if(j) y=sum[k][j-1][0]*((sum[i-k][j-1][1]+sum[i-k][j-1][0])%mod)%mod;
//这里是前缀和优化
else y=0;
dp[i][j][1]=(dp[i][j][1]+(x-y+mod)%mod*C[i][k]%mod)%mod;
}
if(j){
dp[i][j][0]=(dp[i][j][0]+(mod+1-p)%mod*((dp[i-1][j-1][0]+dp[i-1][j-1][1])%mod)%mod)%mod;
dp[i][j][0]=(dp[i][j][0]+p*((dp[i-1][j+1][1]+dp[i-1][j+1][0])%mod)%mod)%mod;
sum[i][j][0]=(sum[i][j-1][0]+dp[i][j][0])%mod;
sum[i][j][1]=(sum[i][j-1][1]+dp[i][j][1])%mod;
}
else{
dp[i][j][0]=(dp[i][j][0]+p*((dp[i-1][j+1][1]+dp[i-1][j+1][0])%mod)%mod)%mod;
dp[i][j][0]=(dp[i][j][0]+p*((dp[i-1][j][1]+dp[i-1][j][0])%mod)%mod)%mod;
sum[i][j][0]=dp[i][j][0];
sum[i][j][1]=dp[i][j][1];
}
}
}
int ans=(dp[n][0][0]+dp[n][0][1])%mod;
for(int i=1;i<=n;i++)
ans=ans*qmi(2*i-1,mod-2)%mod;
cout<<ans<<endl;
}
闲话
这道题赛时有个地方没取模导致挂成10pts(好像也不是)重构了一下就对了。 本题好像套个多项式有更低复杂度??但是不会多项式。