• 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
    ",ans);
    98     return 0;
    99 }
    View Code

    方法三:PAM。不会。

  • 相关阅读:
    第十一周助教小结
    第十周助教小结
    第九周助教小结
    第八周助教小结
    第七周助教小结
    第六周助教小结
    第五周助教小结
    [SHOI2006]有色图
    [JSOI2019]神经网络
    【CF 715E】Complete the Permutations
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8003720.html
Copyright © 2020-2023  润新知