CF835D 回文串

1 CF835D 回文串

2 题目描述

时间限制 \(3s\) | 空间限制 \(256M\)

长度为 \(|s|\) 的字符串 \(s\) 的回文特征是 \(|s|\) 个整数的序列。第 \(k\) 个数字是所有 \(s\) 的非空字串的 \(k\) 回文。一个回文字符串是 \(1\) 回文。一个字符串是 \(k\) 回文当且仅当下面条件成立:

  • 它的左边一半等于右边一半;
  • 它的左边和右边一半都是非空的 \(k-1\) 回文。

左半字符串 \(t\) 的前缀长度为 \(\left\lfloor\frac{|t|}{2}\right\rfloor\),右半字符串是同样长度的后缀。\(\left\lfloor\frac{|t|}{2}\right\rfloor\) 是字符串 \(t\) 的长度除以 \(2\) 以后向下取整。输出给定字符串的所有阶回文串。

数据范围:\(1 ≤ |s| ≤ 5000\)

3 题解

根据题目可以看出,我们可以使用区间 \(dp\) 进行计算。我们设 \(dp_{l, r}\) 表示区间 \([l,r]\) 是几级回文串。如果不是回文串则值为 \(0\)。和之前的回文串有关区间 \(dp\) 类似,我们需要先预处理出 \(dp_{l, l}\) 的值。之后,我们的转移为:

\(1.\)\(s_l \ne s_r\) 或者 \(dp_{l+1, r-1} = 0\),则 \(dp_{l, r} = 0\)

\(2.\)\(s_l = s_r\)\(dp_{l+1, r-1} \ne 0\),那么 \(dp_{l, r} = dp_{l, l + \frac{r - l+1}{2} - 1} + 1\)

统计答案时,我们可以用 \(ans\) 数组先记录每级回文串有多少个,然后再加上所有大于当前回文串级数的回文串个数。

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 5005;
int n;
string s;
int dp[N][N], ans[N];
int main()
{
    cin >> s;
    for (int i = s.length(); i >= 1; i--) s[i] = s[i-1];
    n = s.length();
    for (int i = 1; i <= n; i++) dp[i][i] = 1;
    ans[1] += n;
    for (int len = 2; len <= n; len++)
    {
        for (int l = 1; l <= n - len + 1; l++)
        {
            int r = l + len - 1;
            if (s[l] != s[r] || (l+1 <= r-1 && dp[l+1][r-1] == 0)) dp[l][r] = 0;
            else dp[l][r] = dp[l][l + (r - l + 1) / 2 - 1] + 1;
            ans[dp[l][r]]++;
        }
    }
    for (int i = n; i >= 1; i--) ans[i] += ans[i+1];
    for (int i = 1; i <= n; i++) cout << ans[i] << " ";
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-30 16:33  David24  阅读(73)  评论(0编辑  收藏  举报