題目描述
連結
雖然探索金字塔是極其老套的劇情,但是有一隊探險家還是到了某金字塔腳下。
經過多年的研究,科學家對這座金字塔的内部結構已經有所了解。
首先,金字塔由若幹房間組成,房間之間連有通道。
如果把房間看作節點,通道看作邊的話,整個金字塔呈現一個有根樹結構,節點的子樹之間有序,金字塔有唯一的一個入口通向樹根。
并且,每個房間的牆壁都塗有若幹種顔色的一種。
探險隊員打算進一步了解金字塔的結構,為此,他們使用了一種特殊設計的機器人。
這種機器人會從入口進入金字塔,之後對金字塔進行深度優先周遊。
機器人每進入一個房間(無論是第一次進入還是傳回),都會記錄這個房間的顔色。
最後,機器人會從入口退出金字塔。
顯然,機器人會通路每個房間至少一次,并且穿越每條通道恰好兩次(兩個方向各一次), 然後,機器人會得到一個顔色序列。
但是,探險隊員發現這個顔色序列并不能唯一确定金字塔的結構。
現在他們想請你幫助他們計算,對于一個給定的顔色序列,有多少種可能的結構會得到這個序列。
因為結果可能會非常大,你隻需要輸出答案對 1 0 9 10^9 109 取模之後的值。
輸入描述:
輸入僅一行,包含一個字元串 S S S,長度不超過 300 300 300,表示機器人得到的顔色序列。
輸出描述:
輸出一個整數表示答案。
輸入
ABABABA
輸出
思路
之前做的區間dp題目都是:一個大區間可以看作是兩個小區間合并。
如果這道題規定,金字塔内部結構是一棵二叉樹,那麼和普通的區間dp就一樣了(因為一個區間最多可以看作是兩個區間合并)。
可是它是多叉樹,區間dp的時候要合并多個區間就沒法搞了。
STD是,确定第一棵子樹 d f s dfs dfs 序的範圍。 也就是說,本來是多個區間合并,把它看作是第一個區間和剩下的所有區間合并。
這樣枚舉第一個區間的範圍,就不會漏解。而且又轉化為我們熟悉的兩個區間合并了。
f [ i ] [ j ] = ∑ s [ i ] = s [ k ] , i ≤ k ≤ j f [ i + 1 ] [ k − 1 ] × f [ k ] [ j ] f[i][j]=\sum_{s[i]=s[k],i \le k \le j} f[i+1][k-1] \times f[k][j] f[i][j]=s[i]=s[k],i≤k≤j∑f[i+1][k−1]×f[k][j]
#include<bits/stdc++.h>
using namespace std;
const int N=310,mod=1e9;
char s[N]; int n,f[N][N];
signed main(){
cin>>(s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++) f[i][i]=1;
for(int len=2;len<=n;len++)
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<=j;k++) if(s[i]==s[k])
f[i][j]=(f[i][j]+f[i+1][k-1]*f[k][j])%mod;
}
cout<<f[1][n]<<"\n";
}