题解:CodeForces 835 D Palindromic characteristics[区间dp/马拉车Manacher]
CodeForces 835D
D. Palindromic characteristics
time limit per test: 3 seconds
memory limit per test: 256 megabytes
*inputstandard input
outputstandard output
Palindromic characteristics of string \(s\) with length \(|s|\) is a sequence of \(|s|\) integers, where \(k\)-th number is the total number of non-empty substrings of \(s\) which are \(k\)-palindromes.
- A string is \(1\)-palindrome if and only if it reads the same backward as forward.
- A string is \(k\)-palindrome \((k > 1)\) if and only if:
Its left half equals to its right half.
Its left and right halfs are non-empty \((k - 1)\)-palindromes.
The left half of string \(t\) is its prefix of length \(⌊|t| / 2⌋\), and right half — the suffix of the same length. \(⌊|t| / 2⌋\) denotes the length of string \(t\) divided by \(2\), rounded down.
Note that each substring is counted as many times as it appears in the string. For example, in the string "aaa" the substring "a" appears \(3\) times.
Input
The first line contains the string \(s\) \((1 ≤ |s| ≤ 5000)\) consisting of lowercase English letters.
Output
Print \(|s|\) integers — palindromic characteristics of string \(s\).
Examples
input
abba
output
6 1 0 0
input
abacaba
output
12 4 1 0 0 0 0
Note
In the first example \(1\)-palindromes are substring «a», «b», «b», «a», «bb», «abba», the substring «bb» is \(2\)-palindrome. There are no \(3\)- and \(4\)-palindromes here.
我的题解
一题比较简单的字符串dp
假设字符串长度为l
用一个二维数组记录两个字符之间的字符串是否为回文字符串(或者说组成了多少级别的回文字符串)
再用一个数组计数,该等级的回文字符串有多少个
先把自己组成回文字符串的挑出来(字符串长度为1)
再把和相邻的字符组成回文字符串的挑出来(字符串长度为2)
然后从3到n遍历字符串长度
检测是否存在该长度字符串为回文字符串
(只要看除了左右端点的也就是内部的字符串是否为回文字符串 和 左右两个字符是否相同 就可以了)
如果不是就continue
如果是就找这是多少级别的
只要查询最左边字符与中间字符之间的字符串构成多少级别的字符串再加一就可以了
找到最中间字符要对字符串长度分奇偶判断
That's all!
7.14更新: 预处理可以用马拉车Manacher 但是我还不会
我的代码:
#include <bits/stdc++.h>
#define int long long
const int N = 1e4/2 + 2;
int dp[N][N];
int k[N];
int n;
signed main()
{
std::string s;
std::cin >> s;
n = s.size();
for(int i = 0 ; i < n ; i ++)
{
dp[i][i] += 1;
k[1] ++;
if(i < n-1 && s[i] == s[i+1])
{
dp[i][i+1] += 2;
k[1] ++;
k[2] ++;
}
}
for(int i = 3 ; i <= n ; i ++)
{
for(int j = 0 ; j+i-1 < n ; j ++)
{
int l = j , r = l+i-1;
if(!dp[l+1][r-1] || s[l] != s[r]) continue;
int mid = l + r >> 1;
if(i&1) dp[l][r] = dp[j][mid-1] + 1;
else dp[l][r] = dp[j][mid] + 1;
for(int p = dp[l][r] ; p > 0 ; p --)
{
k[p]++;
}
}
}
for(int i = 1 ; i <= n ; i ++) std::cout << k[i] << " ";
return 0;
}
PS:
思路来自大佬题解指路
有什么出现纰漏的地方还请大家在评论区指出!谢谢!
posted on 2024-07-14 14:07 Jiejiejiang 阅读(1) 评论(0) 编辑 收藏 举报