【BZOJ3676&UOJ103】回文串(manacher,Trie,回文自动机)

题意:考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度。

请你求出s的所有回文子串中的最大出现值。

len<=300000

思路:

做法一:manacher+Trie

鸣谢UOJ上ID为nothing100的小哥(小姐姐?)

学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\n",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 }

 

posted on 2017-04-14 20:23  myx12345  阅读(218)  评论(0编辑  收藏  举报

导航