题目链接https://tianchi.aliyun.com/oj/14491652514320995/73733636160164531
思路
用dp[j][i]表示[j,i]区间内的最长对称前后缀的一半(区间长度为奇数则不算中间那个数)。
转移方程: d p [ j ] [ i ] = d p [ j + 1 ] [ i − 1 ] + 1 dp[j][i]=dp[j+1][i-1]+1 dp[j][i]=dp[j+1][i−1]+1
考虑两种情况:
①[j,i]区间内最长对称前后缀重合。
例如aba,此时dp[0][2]=1,对于[0,2]区间,ans+=2*dp[0][2]+1。
例如abba,此时dp[1][2]=1,dp[0][3]=2,对于[0,3]区间,ans+=2*dp[0][3]。
②[j,i]区间内最长对称前后缀被隔断(无法重合)。
例如abca,此时dp[0][3]=1,对于[0,3]区间,ans+=dp[0][3]。
方便本地调试的代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e3+10;
int dp[N][N];
int main()
{
string s;
cin>>s;
int sz=s.length();
long long ans=(long long)sz;
vector<int>g[26];
memset(dp,0,sizeof(dp));
for(int i=0;i<26;i++)
g[i].clear();
for(int i=0;i<sz;i++)
{
int x=s[i]-'a';
g[x].push_back(i); // g[x]保存字母x的所有位置
int n=(int)g[x].size();
if(n>1)
{
for(int k=0;k<n-1;k++)
{
int j=g[x][k]; // j <- i
int d=i-j+1;
dp[j][i]=dp[j+1][i-1]+1;
ans+=dp[j][i];
if(d%2==1&&dp[j][i]*2+1==d)ans+=dp[j][i]+1; // 例如:aba
else if(d%2==0&&dp[j][i]*2==d)ans+=dp[j][i]; // 例如:abba
}
}
}
printf("%lld\n",ans);
return 0;
}
/*
aba
ans:6
abba
ans:10
aa
ans:4
aaa
ans:10
aaaa
ans:20
bacbdab
ans:12
abcca
ans:8
abcc
ans:6
bdcabcd
ans:11
abccbac
ans:21
*/
最终提交的代码
const int N=3e3+10;
int dp[N][N];
class Solution {
public:
/**
* @param s: a string.
* @return: return the values of all the intervals.
*/
long long suffixQuery(string &s) {
int sz=s.length();
long long ans=(long long)sz;
vector<int>g[26];
memset(dp,0,sizeof(dp)); // 一定要初始化!否则wa!
for(int i=0;i<26;i++)
g[i].clear();
for(int i=0;i<sz;i++)
{
int x=s[i]-'a';
g[x].push_back(i); // g[x]保存字母x的所有位置
int n=(int)g[x].size();
if(n>1)
{
for(int k=0;k<n-1;k++)
{
int j=g[x][k]; // j <- i
int d=i-j+1;
dp[j][i]=dp[j+1][i-1]+1;
ans+=dp[j][i];
if(d%2==1&&dp[j][i]*2+1==d)ans+=dp[j][i]+1; // 例如:aba
else if(d%2==0&&dp[j][i]*2==d)ans+=dp[j][i]; // 例如:abba
}
}
}
return ans;
}
};
(class中dp数组没有memset,wa了无数次)