模拟考是碰到的,以前听过但没有做过,当场推出来了。
题面
题意就是给你一个串,定义字串的得分为长度*出现次数,问所有回文串中的最大得分。
题目分析:回文串当然首推manacher算法,只有当右指针右移时才会出现本质不同的回文串,得到该串的l和r,然后就是统计该串出现次数,很水的的我只会SAM了。
SAM的每个状态的所有串互为后缀,还记下了Right集,大小即为这个状态所有串的出现次数,还有Min和Max,表示这些串的长度范围,Min=Max(pre)+1。
先找到插入第r个字符时的状态,然后以Max为二分依据在parent树上倍增,找到字串[l,r]所属的状态,并统计答案。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=300300,mo=1e9+7;
char s[N],ss[2*N];
int n;
int last=1,cur=1;
int pos[N],dep[2*N],pre[2*N],son[2*N][26],fa[2*N][20],siz[2*N];
int bl[N*2];
LL ans;
struct yy
{
int num,de;
}f[N*2];
bool cmp(yy x,yy y)
{
return x.de<y.de;
}
void insert(int x,int id)
{
dep[++cur]=dep[last]+1;
int np=cur,p=last;
last=cur;
pos[id]=cur;
siz[cur]=1;
for(;!son[p][x];p=pre[p])
son[p][x]=np;
if(!p)
pre[np]=1;
else
{
int q=son[p][x];
if(dep[q]==dep[p]+1)
pre[np]=q;
else
{
dep[++cur]=dep[p]+1;
int nq=cur;
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
mmcp(son[nq],son[q]);
for(;son[p][x]==q;p=pre[p])
son[p][x]=nq;
}
}
}
void query(int l,int r)
{
if(l%2==0||r%2==0)
return;
l=(l+1)/2;
r=(r+1)/2;
int mid=pos[r];
for(int j=18;j>=0;j--)
{
int t=fa[mid][j];
if(dep[t]>=r-l+1)
mid=t;
}
ans=max(ans,1ll*(r-l+1)*siz[mid]);
}
void manacher()
{
int ret=0,mx=0,id=0;
bl[0]=1;
for(int i=0;i<=n;i++)
ss[i*2]='&';
for(int i=0;i<n;i++)
ss[i*2+1]=s[i];
ss[2*n]='!';
for(int i=1;i<n*2+1;i++)
{
if(mx>i)
bl[i]=min(bl[2*id-i],mx-i);
else {
bl[i]=1;
query(i,i);
}
while(ss[i-bl[i]]==ss[i+bl[i]])
{
query(i-bl[i],i+bl[i]);
bl[i]++;
}
if(mx<=bl[i]+i)
mx=bl[i]+i-1,id=i;
}
}
int main()
{
freopen("2115.in", "r", stdin);
freopen("2115.out", "w", stdout);
scanf("%s",s);
n=strlen(s);
for(int i=0;i<n;i++)
insert(s[i]-'a',i+1);
for(int i=1;i<=cur;i++)
fa[i][0]=pre[i];
fa[1][0]=1;
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=1;i<=cur;i++)
{
f[i].num=i;
f[i].de=dep[i];
}
sort(f+1,f+cur+1,cmp);
for(int i=cur;i>=1;i--)
{
int hy=f[i].num;
siz[pre[hy]]+=siz[hy];
}
manacher();
cout<<ans<<endl;
return 0;
}