- O(n^2)的DP是显然的,但没有优化思路。考虑证伪数据范围。发现n>2600时,根据抽屉原理,一定有一个字符出现了至少101次。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int f[3005][3005];
int g[3005][3005];
char s[50005];
int cnt[30],pi,pj;
string tmp="";
void solve(int maxn)
{
string ans1="";
while(ans1.size()<maxn)
{
if(g[pi][pj]==3)
{
ans1+=s[pi];
pi--;
pj++;
}
else if(g[pi][pj]==2)
{
pj++;
}
else
{
pi--;
}
}
string ans2=ans1;
reverse(ans1.begin(),ans1.end());
cout<<ans1<<tmp<<ans2<<endl;
}
int main()
{
string t;
cin>>t;
int n=t.size();
if(n>=2600)
{
for(int i=0;i<n;i++)
{
cnt[t[i]-'a']++;
if(cnt[t[i]-'a']>=100)
{
for(int j=0;j<100;j++)
{
cout<<t[i];
}
cout<<endl;
return 0;
}
}
}
for(int i=1;i<=n;i++)
{
s[i]=t[i-1];
}
pi=0,pj=n+1;
for(int i=1;i<=n;i++)
{
for(int j=n;j>=i+1;j--)
{
if(f[i-1][j]>f[i][j+1])
{
f[i][j]=f[i-1][j];
g[i][j]=1;
}
else
{
f[i][j]=f[i][j+1];
g[i][j]=2;
}
if(s[i]==s[j]&&f[i-1][j+1]+1>f[i][j])
{
f[i][j]=f[i-1][j+1]+1;
g[i][j]=3;
}
if(f[i][j]>f[pi][pj]||f[i][j]==f[pi][pj]&&j-i>pj-pi)
{
pi=i;
pj=j;
}
if(f[i][j]==50)
{
pi=i;
pj=j;
solve(50);
return 0;
}
}
}
int maxn=f[pi][pj];
if(pj!=pi+1)
{
tmp+=s[pi+1];
}
solve(maxn);
return 0;
}