给定一个字符串s,对s进行删除操作,使得剩下的子串是回文字符串,问最多有多少种这种子串。
直接从题意切入:dp[i, j]表示区间[i, j]最多有多少个这样的子串。
1. s[i] == s[j] 去掉s[i],则一个子问题就是dp[i+1, j],去掉s[j],另一个子问题就是dp[i, j-1]。
显然这两个子问题是会有重叠的,比如去掉s[i], s[j]的dp[i+1, j-1]。
如果s[i],s[j]都不去掉呢?则这个子问题的解显然是dp[i+1, j-1] + 1。
于是会有 dp[i][j] = dp[i+1][j] + dp[i][j-1] + 1;
2. s[i] != s[j] 此时的子问题就比上述要简单了,因为s[i] s[j]与dp[i+1, j-1]的回文子串构成不了回文串。
直接从题意切入:dp[i, j]表示区间[i, j]最多有多少个这样的子串。
1. s[i] == s[j] 去掉s[i],则一个子问题就是dp[i+1, j],去掉s[j],另一个子问题就是dp[i, j-1]。
显然这两个子问题是会有重叠的,比如去掉s[i], s[j]的dp[i+1, j-1]。
如果s[i],s[j]都不去掉呢?则这个子问题的解显然是dp[i+1, j-1] + 1。
于是会有 dp[i][j] = dp[i+1][j] + dp[i][j-1] + 1;
2. s[i] != s[j] 此时的子问题就比上述要简单了,因为s[i] s[j]与dp[i+1, j-1]的回文子串构成不了回文串。
于是 dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1];
typedef long long LL ;
const int maxn = 68 ;
char str[maxn] ;
LL dp[maxn][maxn] ;
LL DP(int l , int r){
if(l > r) return dp[l][r] = 0 ;
if(dp[l][r] != -1) return dp[l][r] ;
if(l == r) return dp[l][r] = 1 ;
if(str[l] == str[r])
return dp[l][r] = DP(l+1 , r) + DP(l , r-1) + 1 ;
else
return dp[l][r] = DP(l+1 , r) + DP(l , r-1) - DP(l+1 , r-1) ;
}
int main(){
int t ;
cin>>t ;
while(t--){
scanf("%s" , str) ;
memset(dp , -1 , sizeof(dp)) ;
printf("%lld\n" , DP(0 , strlen(str) - 1) ) ;
}
return 0 ;
}