Luogu P10956 金字塔

Solution

考虑区间 dp。很容易想到定义 \(dp_{l,r}\) 表示区间 \([l,r]\) 对应的满足条件的子树的方案数。

一般区间 dp 的套路无非就是枚举一个断点 \(k\),使得这个大状态由两个小状态转移过来,我们现在需要考虑的就是如何划分每一个状态。

状态对应的子树也有若干个子树。不妨只考虑第一棵子树是什么样的,这样我们将整个状态划分成了第一棵子树和其他子树。所以考虑递归地把每一个 \(dp_{l,r}\) 计算。具体地,每次依然枚举一个断点 \(k\),分割第一棵子树和其他子树,再分别递归计算第一棵子树和其他子树的答案。

下面假设每一个 \(dp_{l,r}\) 已经算出,那么:

\[dp_{l,r}=\sum^{r}_{k=l+2}dp_{l+1,k-1} \times dp_{k,r} \]

Code

使用的是记忆化搜索。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9;
string str;
int n,dp[305][305];
int dfs(int l,int r){
	if(l>r) return 0;
	if(l==r) return 1;
	if(str[l]!=str[r]) return 0;
	if(dp[l][r]!=-1) return dp[l][r];
	dp[l][r] = 0;
	for(int i=l+2;i<=r;i++){
		if(str[l]==str[i]) dp[l][r]=(dp[l][r]+dfs(l+1,i-1)*dfs(i,r))%mod;
	}
	return dp[l][r];
}
signed main(){
	cin>>str;
	n=str.size();
	str=" "+str;
	for(int i=1;i<=n;i++){
	    for(int j=i;j<=n;j++){
	        dp[i][j]=-1;
	    }
	}
	cout<<dfs(1,n)<<endl;
	return 0;
}
posted @ 2024-09-24 17:00  HAM_qwq  阅读(5)  评论(0编辑  收藏  举报