題意:
k-迴文的定義:
1.它的左半部分等於右半部分,即本身是1-迴文。
2.它的左半部分和右半部分都是(k-1)-迴文,奇數長度不考慮正中間。
給你一串長度爲n的字符串,讓你統計其所有子串中,是1-迴文到n-迴文的個數,並輸出。
思路:
1.暴力枚舉所有子串,計算它們的最高迴文等級。
2.dp[i][j]
表示從第i位到第j位的最高迴文等級爲dp[i][j]
。
3.預處理長度小於等於2的子串。
4.先判斷計算的子串是不是迴文串,如果不是迴文串則dp[i][j] = 0
。如果是迴文串,即滿足題意中的1。
5.計算的子串長度爲偶數時,dp[l][r] = dp[l][mid] + 1
。
6.計算的子串長度爲奇數時,dp[l][r] = dp[l][mid-1] + 1
。
7.統計一下後綴和就是結果,因爲k迴文一定是k-1迴文。
代碼:
#include <bits/stdc++.h>
using namespace std;
int dp[5050][5050];
int ans[5050];
int main() {
string s;
cin >> s;
int n = s.size();
memset(ans, 0, sizeof(ans));
memset(dp, 0, sizeof(dp));
for(int i = 0; i < n; ++ i)
dp[i][i] = 1;
for(int i = 0; i < n - 1; ++ i)
dp[i][i+1] = (s[i] == s[i+1] ? 2 : 0);
for(int len = 3; len <= n; ++ len) {
for(int l = 0; l <= n - len; ++ l) {
int r = l + len - 1;
if(s[l] != s[r] || dp[l + 1][r - 1] == 0) {
dp[l][r] = 0;
continue;
}
int mid = l + r >> 1;
if(len % 2 == 0) {
dp[l][r] = dp[l][mid] + 1;
} else {
dp[l][r] = dp[l][mid - 1] + 1;
}
}
}
for(int len = 1; len <= n; ++ len) {
for(int l = 0; l <= n - len; ++ l) {
ans[dp[l][l + len - 1]]++;
}
}
for(int i = n - 1; i >= 1; -- i) {
ans[i] += ans[i + 1];
}
for(int i = 1; i <= n; ++ i) {
if(i > 1) putchar(' ');
printf("%d", ans[i]);
}
putchar('\n');
}