CF427D(Div2) Palindromic characteristics
题目链接
这是一道区间DP题,我们可以首先标记一下是回文串的区间,然后对字符串内的每个区间依次求解就行,
这个求解过程可以使用标准的DP(区间大小依次增大,依次求解),
也可以使用记忆化搜索(不需要特定顺序,只要保证每个区间只更新一次就行),
在我的代码中,我使用的是记忆化搜索
根据题目复杂度(|S|<5000),在回文串判断上不需要使用优化算法,
朴素的O(n^2)判断就已经足够了
#include <bits/stdc++.h>
const int MAXN=5000+5;
bool dp1[MAXN][MAXN];
int dp2[MAXN][MAXN];
int kinds[MAXN];
char str[MAXN];
int len;
//记忆化搜索
int getNum(int L,int R)
{
if(dp2[L][R]==-1)
{
if(dp1[L][R])
{
dp2[L][R]=getNum(L,(L+R-1)/2)+1;
//增长计数
kinds[dp2[L][R]]++;
//输出测试(被更新的区间):printf("%d %d %d\n",L,R,dp2[L][R]);
}
else
dp2[L][R]=0;
}
return dp2[L][R];
}
int main()
{
int main;
memset(kinds,0,sizeof(kinds));
memset(dp1,0,sizeof(dp1));
memset(dp2,-1,sizeof(dp2));
scanf("%s",&str);
len=strlen(str);
for(int i=0;i<len;i++)
{
dp1[i][i]=dp1[i][i-1]=true;
dp2[i][i]=dp2[i][i-1]=true;
kinds[1]++;
}
//更新数值
for(int i=0;i<len;i++)
{
int l=1;
while(i-l>=0&&i+l<len&&str[i-l]==str[i+l])
{
dp1[i-l][i+l]=true;
l++;
}
l=1;
while(i-l>=0&&i-1+l<len&&str[i-l]==str[i-1+l])
{
dp1[i-l][i-1+l]=true;
l++;
}
}
//区间搜索
for(int i=0;i<len;i++)
for(int j=i+1;j<len;j++)
getNum(i,j);
for(int i=len-1;i>=1;i--)
kinds[i]+=kinds[i+1];
//输出答案
for(int i=1;i<=len;i++)
{
if(i==len)
printf("%d\n",kinds[i]);
else
printf("%d ",kinds[i]);
}
}