题意:
给出一棵多叉树,每个节点的任意两个子节点都有左右之分。从根节点开始,每次尽量往左走,走不动就回溯,把遇到的字母顺序记录下来,得到一个序列。现在给一个序列,问有多少棵树与之对应。
DP[i][j]表示序列i..j对应的树的数量
则 dp[i][j] = sum(dp[i+1][k-1] * dp[k][j])
看大白上的图就非常直观了
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
const int INF = 0x3f3f3f3f;
const double eps = 10e-9;
const double PI = (4.0*atan(1.0));
const int maxn = 300 + 20;
const int MOD = 1000000000;
char str[maxn];
int dp[maxn][maxn];
int f(int s, int e) {
if(s == e) return 1;
if(dp[s][e] != -1) return dp[s][e];
if(str[s] != str[e]) return 0;
int & ans = dp[s][e];
ans = 0;
for(int i=s+1; i<=e; i++) if(str[e] == str[i]) {
ans = (ans + (LL) f(s+1, i-1) * f(i, e)) % MOD;
}
return ans;
}
int main() {
while(scanf("%s", str) != EOF) {
memset(dp, -1, sizeof(dp));
int n = strlen(str);
int ans = f(0, n-1);
printf("%d\n", ans);
}
return 0;
}