题意:定义1阶回文串:从左到右读等于从右到左读。k(k>=2)阶回文串为:本身是1阶回文串,且左半边和右半边都是k-1阶回文串。左半边:[ l , l+(r-l+1)/2-1 ];右半边:[ r-(r-l+1)/2+1 , r ]。求阶数为 1 到 len 的回文字串的个数。
题解:子问题!子问题!子问题!k阶回文串的第一个定义:自身是回文串,这个等价于s[ l+1 ][ r-1 ]是一个回文串 && s[ l ] == s[ r ]。第二个条件:左半边和右半边都是 k-1 阶回文串,显然当[ l .. r ]字串是一个回文串的时候,左右半边的阶数是相同的。那么我们可以按照长度来进行 dp ,这样保证在算[ l .. r ]最大的阶数的时候,左右半串都已经算完了。最后一个问题:一个k阶回文串,按照定义,他也是k-1阶,k-2阶……1阶回文串,因此我们只需要确定字串的最大阶就可以了。
dp[ l ][ r ]表示s[ l .. r ]的最大阶数。cot[ x ]表示 x阶串总共有cot[ x ]个。代码简单易懂,稍微注意一下初始条件就没问题了。
Code:
#include<bits/stdc++.h>
using namespace std;
const int MAX = 5050;
char s[MAX];
int dp[MAX][MAX];
int cot[MAX];
int ans[MAX];
int main(){
scanf("%s",s);
int len = strlen (s);
for (int i=0;i<=len;i++){
dp[i][i] = 1;
dp[i][i-1] = 1;
}
cot[1] = len;
for (int k=2;k<=len;k++){
for (int l = 0;l<=len-k;l++){
int r = l+k-1;
if (s[l]==s[r]&&dp[l+1][r-1]){
dp[l][r] = dp[l][l-1+((r-l+1)>>1)]+1;
// printf("dp[%d][%d]:%d\n",l,r,dp[l][r]);
cot[dp[l][r]]++;
}
}
}
int sum =0;
for (int i=len;i>=1;i--){
sum+=cot[i];
ans[i] = sum;
}
for (int i=1;i<=len;i++){
printf("%d ",ans[i]);
}
return 0;
}