设d(i, j)为连续子序列[i, j]构成数的个数,因为遍历从根节点出发最终要回溯到根节点,所以边界情况是:d(i, i) = 1; 如果s[i] != s[j], d(i, j) = 0
假设第一个分支在Sk回到根节点,方案数为d(i+1, k-1)
其他分支访问从Sk到Sj,方案数为d(k, j)
根据乘法原理,d(i, j) = sum{d(i+1, k-1), d(k, j), i+2≤k≤j 且 Si = Sk = Sj}
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int maxn = 300 + 10; 7 const int MOD = 1000000000; 8 9 char s[maxn]; 10 int d[maxn][maxn]; 11 12 int dp(int i, int j) 13 { 14 if(i == j) return 1; 15 if(s[i] != s[j]) return 0; 16 int& ans = d[i][j]; 17 if(ans >= 0) return ans; 18 19 ans = 0; 20 for(int k = i + 2; k <= j; k++) if(s[i] == s[k]) 21 ans = (ans + (LL)dp(i+1, k-1) * (LL)dp(k, j)) % MOD; 22 return ans; 23 } 24 25 int main() 26 { 27 while(scanf("%s", s) == 1) 28 { 29 memset(d, -1, sizeof(d)); 30 printf("%d ", dp(0, strlen(s) - 1)); 31 } 32 33 return 0; 34 }