CF835D Solution

题目链接

题解

因为长度为\(i\)\(k\)阶回文串一定由2个长度为\(\lfloor\frac{i}{2} \rfloor\)\(k-1\)阶回文串组成,可以想到区间dp。

状态:\(dp[l][r]\)表示回文子串\([l,r]\)的阶数(若不是回文串为\(0\))。

转移方程:

\[dp[l][r]=dp[l][(l+r-1)/2]+1\quad (1\le l<r\le n,r-l\ge 2,dp[l+1][r-1]>0,s_l=s_r)\\ dp[l][l]=1\quad (1\le l\le n)\\ dp[l][l+1]=2\quad (1\le l<n,s_l=s_{l+1}) \]

易得,当区间\([l+1,r-1]\)为回文子串且\(s_l=s_r\)时,区间\([l,r]\)为回文子串,而其阶数等于左/右半部分阶数\(+1\)。长度为\(1/2\)的回文子串需特殊处理。

答案:设\(sum_i\)表示\(i\)阶回文子串的个数,\(sum_i=\sum dp[l][r]\quad (dp[l][r]=i)\)。因为\(k\)阶回文子串同时为\([1,k-1]\)阶回文子串,需对\(sum\)数组求后缀和。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=5010;
char s[N];
int dp[N][N],sum[N];
int main()
{
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n;i++)
	{
		if(s[i]==s[i+1]) dp[i][i+1]=2,sum[2]++;
		dp[i][i]=1; sum[1]++;
	}
	for(int i=2;i<=n;i++)
	{
		for(int l=1;l+i<=n;l++)
		{
			int r=l+i;
			if(!dp[l+1][r-1] || s[l]!=s[r]) continue;
			dp[l][r]=dp[l][(l+r-1)/2]+1; sum[dp[l][r]]++;
		}
	}
	for(int i=n;i>=1;i--) sum[i]+=sum[i+1];
	for(int i=1;i<=n;i++) printf("%d ",sum[i]);
	return 0;
}
posted @ 2021-02-04 21:07  violet_holmes  阅读(65)  评论(0编辑  收藏  举报