传送门
设dp[l][r]为序列l至r代表的子树的个数,由DFS序的特性可以知道,如果要一棵完整的子树的DFS序两端的序号是一样的,都是树根的编号。这里状态方程的巧妙之处就在于,运用乘法原理,保证了状态不会有重复。即对于区间l至r,枚举点k,如果s[l+1] == s[k-1]且s[k] == s[r],说明区间[l+1, k-1]和区间[k, r]可以构成两棵子树
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
const long long MOD = 1e9;
long long dp[305][305]; //dp[l][r]表示区间l至r区间可以表示的个数
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
char s[305];
cin >> (s+1);
int slen = strlen(s+1);
for(int i = 1; i <= slen; ++i) dp[i][i] = 1;
for(int len = 2; len <= slen; ++len){
for(int l = 1; l +len-1 <= slen; ++l){
int r = l+len-1;
dp[l][r] = 0;
if(s[l] != s[r]) continue;
for(int k = l+2; k <= r; ++k){
if(s[k] == s[r] && s[l+1] == s[k-1])
dp[l][r] = (dp[l][r] + dp[l+1][k-1]*dp[k][r]%MOD) % MOD;
}
}
}
cout << dp[1][slen] << endl;
return 0;
}