题解:P10956 金字塔

对于 dfs 序, 由于题目的要求是进入还是返回都会记录颜色, 那么我们可以考虑把问题的规模进行缩小。

\(dp_{i,j}\) 代表以区间 \([i,j]\) 可行的方案数。
显然 \(dp_{i,j}\) 可以从 \(dp_{i-1,j-1}\) 转化而来(大区间可以从小区间转移过来)。

此外,根据 dfs 序的特性,当出现 \(s_l=s_r\) 的时候,可以令 \(1\) 为根,使得 \([l,r]\) 作为以 \(1\) 为根的深度优先遍历的结果。
最后,我们可以枚举一个中间点 \(mid\), 如果出现 \(s_l=s_{mid}=s_r\),证明可以把 \([l,r]\) 划分成两个子树 \([l+1,mid−1]\), \([mid,r]\), 所以是 \(dp_{i,j} \gets dp_{l+1,mid-1}\cdot dp_{mid,r}+dp_{i,j}\)(两个子树的方案都可以随意排列组合)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e2+10;
const int mod=1e9;
char s[maxn];
int dp[maxn][maxn];
int main(){
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n;i++)	dp[i][i]=1;
	for(int l=n-1;l>=1;l--)
		for(int r=l+1;r<=n;r++){
			if(s[l]==s[r]){
				for(int k=l+2;k<=r;k++)
					dp[l][r]=(dp[l][r]+1LL*dp[l+1][k-1]*dp[k][r]%mod)%mod;
			}
		}
	cout<<dp[1][n]<<endl;
}
posted @ 2024-09-16 11:35  cly312  阅读(33)  评论(0)    收藏  举报