题意:考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度。
请你求出s的所有回文子串中的最大出现值。
len<=300000
思路:
做法一:manacher+Trie
学P一时爽,转C火葬场
考虑不同的回文子串中间也是有子串关系的,并且互不包含的极长回文子串的数量是O(n)级别的
所以可先用manacher算出每个位置的最长回文半径
将它们表示成一棵树的形状,一个节点的儿子是它所代表的子串向两侧扩展一个相同字母的串
判断是否是父子关系可以用hash
最后dfs一遍求子树大小就行了,注意需要双hash,C党hash后可以用map和makepair
讲道理C党到这里就能做了,问题我是P党
考虑到刚才那棵树,如果你每个串都只取后半段,那么它是一颗Trie树
所以可以用和刚才类似的方法,而且并不需要hash
manacher过程中
i关于id的对称中心j,mx>i时:
如果p[j]>mx-i则p[i]需要从p[j]开始退格,依次删除最后一个字符直到到达mx-i为止
否则p[i]即为p[j]
mx<=i时说明当前只有i一个字符,就从头开始扩展
UOJ上过了,BZ上没过,残念……
1 var map:array[1..610000,1..29]of longint; 2 fa,size,p,f,a,h:array[1..610000]of longint; 3 n,m,i,j,mx,id,cnt,len:longint; 4 ans:int64; 5 ch:char; 6 7 function min(x,y:longint):longint; 8 begin 9 if x<y then exit(x); 10 exit(y); 11 end; 12 13 function max(x,y:int64):int64; 14 begin 15 if x>y then exit(x); 16 exit(y); 17 end; 18 19 function get(x,y:longint):longint; 20 begin 21 if map[x,y]=0 then 22 begin 23 inc(cnt); 24 fa[cnt]:=x; 25 map[x,y]:=cnt; 26 end; 27 exit(map[x,y]); 28 end; 29 30 procedure dfs(u,ch:longint;dep:int64); 31 var i,v:longint; 32 begin 33 for i:=1 to 29 do 34 begin 35 v:=map[u,i]; 36 if v>0 then 37 begin 38 dfs(v,i,dep+1); 39 size[u]:=size[u]+size[v]; 40 end; 41 end; 42 if ch<27 then ans:=max(ans,dep*size[u]); 43 end; 44 45 begin 46 assign(input,'bzoj3676.in'); reset(input); 47 assign(output,'bzoj3676.out'); rewrite(output); 48 49 n:=2; a[1]:=27; a[2]:=28; 50 while not eoln do 51 begin 52 read(ch); 53 inc(n); a[n]:=ord(ch)-ord('a')+1; 54 inc(n); a[n]:=28; 55 end; 56 inc(n); a[n]:=29; 57 mx:=0; id:=0; cnt:=1; 58 for i:=2 to n-1 do 59 begin 60 if mx>i then 61 begin 62 p[i]:=p[id*2-i]; h[i]:=h[id*2-i]; 63 if p[i]>mx-i then 64 begin 65 for j:=p[i]-1 downto mx-i do h[i]:=fa[h[i]]; 66 p[i]:=mx-i; 67 end; 68 end 69 else 70 begin 71 h[i]:=get(1,a[i]); 72 p[i]:=1; 73 end; 74 while a[i-p[i]]=a[i+p[i]] do 75 begin 76 h[i]:=get(h[i],a[i-p[i]]); 77 inc(p[i]); 78 end; 79 if p[i]+i>mx then 80 begin 81 mx:=p[i]+i; id:=i; 82 end; 83 inc(size[h[i]]); 84 end; 85 dfs(1,27,0); 86 writeln(ans); 87 close(input); 88 close(output); 89 end.
做法2:回文自动机板子
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned int uint; 5 typedef unsigned long long ull; 6 typedef pair<int,int> PII; 7 typedef pair<ll,ll> Pll; 8 typedef vector<int> VI; 9 typedef vector<PII> VII; 10 typedef pair<ll,int>P; 11 #define N 300010 12 #define M 210000 13 #define fi first 14 #define se second 15 #define MP make_pair 16 #define pi acos(-1) 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++) 19 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--) 20 #define lowbit(x) x&(-x) 21 #define Rand (rand()*(1<<16)+rand()) 22 #define id(x) ((x)<=B?(x):m-n/(x)+1) 23 #define ls p<<1 24 #define rs p<<1|1 25 26 const int MOD=998244353,inv2=(MOD+1)/2; 27 double eps=1e-6; 28 int INF=1<<29; 29 ll inf=5e13; 30 int dx[4]={-1,1,0,0}; 31 int dy[4]={0,0,-1,1}; 32 33 char s[N]; 34 int n; 35 36 struct pam 37 { 38 int q,p,id,cnt[N],num[N],f[N],len[N],t[N][26]; 39 40 pam() 41 { 42 id=1; f[0]=f[1]=1; len[1]=-1; 43 } 44 45 void add(int x,int n) 46 { 47 while(s[n-len[p]-1]!=s[n]) p=f[p]; 48 if(!t[p][x]) 49 { 50 int q=++id,k=f[p]; 51 len[q]=len[p]+2; 52 while(s[n-len[k]-1]!=s[n]) k=f[k]; 53 f[q]=t[k][x]; 54 t[p][x]=q; 55 num[q]=num[f[q]]+1; 56 } 57 p=t[p][x]; 58 cnt[p]++; 59 } 60 61 void solve() 62 { 63 ll ans=0; 64 per(i,id,1) 65 { 66 cnt[f[i]]+=cnt[i]; 67 ans=max(ans,1ll*cnt[i]*len[i]); 68 } 69 printf("%lld ",ans); 70 } 71 72 }pam; 73 74 int read() 75 { 76 int v=0,f=1; 77 char c=getchar(); 78 while(c<48||57<c) {if(c=='-') f=-1; c=getchar();} 79 while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar(); 80 return v*f; 81 } 82 83 int main() 84 { 85 //freopen("1.in","r",stdin); 86 87 scanf("%s",s+1); 88 n=strlen(s+1); 89 rep(i,1,n) pam.add(s[i]-'a',i); 90 pam.solve(); 91 return 0; 92 }