1 条题解
-
0
题意
给定一个字符串,定义 回文串如下:
- 一个字符串是 回文串,当且仅当它本身是回文串,且它的左半部分(非空)是 回文串。
- 特别地, 回文串定义为任意字符串。
要求统计原字符串中所有子串中,分别是 回文串、 回文串、…… 的子串数量。
思路
观察 I
如果一个字符串是 回文串,那么它也是 回文串。观察 II
一个字符串是 回文串,当且仅当同时满足以下两个条件:- 它本身是回文串。
- 它的左半部分(非空)是 回文串。
基于以上观察,我们可以通过动态规划求出每个子串的最大 值,再通过后缀和统计答案。
算法步骤
- 定义 表示子串 的最大 值(即它是 回文串,但不是 回文串)。
- 按子串长度从小到大计算 值:
- 当 时,(单个字符是 回文串)。
- 当 时,若 ,则 ,否则为 。
- 当 时:
- 如果 或 ,则 。
- 否则,令 ,则 。
- 统计 表示 值恰好为 的子串个数。
- 计算 ,即所有是 回文串的子串数量。
复杂度分析
- 时间复杂度:,因为需要枚举所有子串并计算 值。
- 空间复杂度:,用于存储 数组。
优化方案
注意到字符串最多是 回文串,因此可以将时间复杂度优化为 ,同时将空间复杂度降低到 。
代码说明
- 使用二维数组 存储每个子串的最大 值。
- 按长度递增顺序计算,利用已计算出的较短子串结果。
- 最后通过后缀和统计每个 对应的子串数量。
#include<bits/stdc++.h> #define re register #define ull unsigned long long using namespace std; char c[5005]; ull fac,fro,bac; /* fac计算base的幂 fro计算从前往后的哈希值 bac计算从后往前的哈希值 这里是直接推过去的,也可以预处理一遍 */ int n,dp[5005],ans[5005]; int main(){ scanf("%s",c),n=strlen(c); //注意要把可能影响后面答案的dp清零(也可直接把dp开两维) for(re int j=0;j<n;dp[j++]=0){ fro=bac=0,fac=1; for(re int i=j;i<n;++i){ dp[i]=0,fro=fro*131+c[i],bac=bac+fac*c[i],fac=fac*131; fro^bac?0:++ans[dp[i]=dp[(i-j-1>>1)+j]+1]; } } for(re int i=n;i;--i)ans[i]+=ans[i+1];//后缀和 for(re int i=1;i<=n;++i)printf("%d ",ans[i]); }
- 1
信息
- ID
- 6736
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者