题意:定义k_Palindromic为某个字符串的回文系数,给一个字符串,统计它的所有子串的回文系数。
思路:这里N=5E3,暗示N*N的做法也可以,子串理解为所有前缀的后缀,然后枚举每个前缀,记忆化搜索中先判断当前是不是回文,是的话再递归求解,递归的过程中的所有解都是之前算过的,所以记忆化一下。
const int N = 5e3 + 5;
char Ma[N << 1], s[N];
int r[N << 1];
void Manacher(char s[], int len)
{
int l = 0;
Ma[l++] = '$';
Ma[l++] = '#';
for (int i = 0;i < len;i++)
{
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = 0;
int mx = 0, id = 0;
for (int i = 0;i < l;i++)
{
r[i] = mx > i ? min(r[2 * id - i], mx - i) : 1;
while (Ma[i + r[i]] == Ma[i - r[i]])r[i]++;
if (i + r[i] > mx)
{
mx = i + r[i];
id = i;
}
}
}
int mp[N][N];
int dfs(int L, int R)
{
if (L > R)return mp[L][R] = 0;
if (mp[L][R] != -1)return mp[L][R];
int mid = (2 * L + 2 * R) >> 1;
if (r[mid] - 1 >= (R - L + 1))
{
if ((R - L + 1) & 1)return mp[L][R] = dfs(L, (L + R >> 1) - 1) + 1;
else return mp[L][R] = dfs(L, L + (R - L + 1 >> 1) - 1) + 1;
}
else return mp[L][R] = 0;
}
int main()
{
//freopen("in.txt", "r", stdin);
scanf("%s", s + 1);
int len = strlen(s + 1);
Manacher(s + 1, len);
map<int, int> ans;
memset(mp, -1, sizeof mp);
f(i, 1, len)
{
f(j, 1, i)
{
ans[dfs(j, i)]++;
}
}
ff(i, len, 1)ans[i] += ans[i + 1];
f(i, 1, len)cout << ans[i] << " ";
cout << endl;
return 0;
}