BZOJ3238:[AHOI 2013]差异

求一个字符串的∑ ∑ len[i] + len[j] - 2 * lcp(i, j),其中i,j表示从i,j开始的后缀。

方法一:SA+单调栈,自行yy。

方法二:SAM构造出来,然后每个状态对答案的贡献就是:C(|right_s|,2)*(Max_s-Max_parent_s)。前面使用的变量名含义与CLJ论文里的一致。right集合的大小需要构造后缀树然后从那些叶子节点开始算。

由于可以用马拉车在O(N)时间内枚举所有的回文串,所以在parent树中倍增找到每个回文串的出现次数即可。

跑得巨慢。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 //#include<iostream>
 6 using namespace std;
 7 
 8 int n;
 9 #define maxn 600011
10 char s[maxn];
11 
12 struct samnode
13 {
14     int ch[26],pre;
15     int pos;
16     samnode() {memset(ch,0,sizeof(ch)); pre=0;}
17 };
18 int pp[maxn],val[maxn];
19 struct SAM
20 {
21     samnode a[maxn];
22     int root,last,size;
23     SAM() {root=1; a[1].pos=0; size=1; last=root;}
24     int idx(char c) {return c-'a';}
25     void insert(char c,int p)
26     {
27         int id=idx(c),x=++size;
28         a[x].pos=p; pp[p]=x; val[x]=1;
29         int y=last;
30         for (;y && !a[y].ch[id];y=a[y].pre) a[y].ch[id]=x;
31         last=x;
32         if (!y) a[x].pre=root;
33         else if (a[a[y].ch[id]].pos==a[y].pos+1) a[x].pre=a[y].ch[id];
34         else
35         {
36             int z=a[y].ch[id],w=++size;
37             a[w]=a[z]; a[w].pos=a[y].pos+1;
38             a[z].pre=a[x].pre=w;
39             for (;y && a[y].ch[id]==z;y=a[y].pre) a[y].ch[id]=w;
40         }
41     }
42 }sam;
43 
44 int list[maxn],fa[maxn][22];
45 bool cmp(const int &i,const int &j) {return sam.a[i].pos>sam.a[j].pos;}
46 void build()
47 {
48     for (int i=1;i<=sam.size;i++) list[i]=i,fa[i][0]=sam.a[i].pre;
49     sort(list+1,list+1+sam.size,cmp);
50     for (int j=1;j<=20;j++)
51         for (int i=1;i<=sam.size;i++)
52             fa[i][j]=fa[fa[i][j-1]][j-1];
53     for (int i=1;i<=sam.size;i++)
54         val[fa[list[i]][0]]+=val[list[i]];
55 }
56 
57 #define LL long long
58 LL getans(int x,int len)
59 {
60     int p=pp[x];
61     for (int j=20;j>=0;j--) if (fa[p][j] && sam.a[fa[p][j]].pos>=len) p=fa[p][j];
62 //    cout<<x<<' '<<len<<' '<<val[p]<<endl;
63     return 1ll*len*val[p];
64 }
65 
66 int mnc[maxn];
67 int main()
68 {
69     scanf("%s",s+1);n=strlen(s+1);
70     for (int i=1;i<=n;i++) sam.insert(s[i],i);
71     build();
72     
73     for (int i=n;i>=1;i--)
74     {
75         s[(i<<1)-1]=s[i];
76         s[i<<1]='#';
77     }
78     n=n+n-1;
79 //    cout<<s+1<<endl;
80     int id=0;LL ans=0;
81     for (int i=1;i<=n;i++)
82     {
83         if (mnc[id]+id>i) mnc[i]=min(mnc[id*2-i],mnc[id]+id-i);
84         else
85         {
86             mnc[i]=1;
87             if (s[i]!='#') ans=max(ans,getans((i+1)>>1,1));
88         }
89         while (i+mnc[i]<=n && i-mnc[i]>0 && s[i+mnc[i]]==s[i-mnc[i]])
90         {
91             if (s[i+mnc[i]]!='#') ans=max(ans,getans((i+mnc[i]+1)>>1,mnc[i]+1));
92             mnc[i]++;
93         }
94         if (mnc[id]+id<mnc[i]+i) id=i;
95 //        cout<<i<<' '<<mnc[i]<<endl;
96     }
97     printf("%lld\n",ans);
98     return 0;
99 }
View Code

方法三:PAM。不会。

posted @ 2017-12-08 20:46  Blue233333  阅读(166)  评论(0编辑  收藏  举报