zoukankan      html  css  js  c++  java
  • [BZOJ4650][NOI2016]优秀的拆分(SAM构建SA)

    关于解法这个讲的很清楚了,主要用了设关键点的巧妙思想。

    主要想说的是一个刚学的方法:通过后缀自动机建立后缀树,再转成后缀数组。

    后缀数组功能强大,但是最令人头疼的地方是模板太难背容易写错。用这个方法,只需要用上SAM的模板即可。

    https://blog.csdn.net/lvzelong2014/article/details/79006541

    反串后缀自动机的parent树就是原串的后缀树,一遍DFS即可求出后缀数组。

    这样代码复杂度上可能稍简单些(在忘记SA模板的时候可以用),构建过程的复杂度也由$O(nlog n)$变为线性,但由于这个线性复杂度是非常满的,所以常常会比SA还要慢不少。注意SAM的数组最好开两倍,一倍是肯定不够的。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mem(a) memset(a,0,sizeof(a))
     5 #define LCP(x,y) SA.que(x,y)
     6 #define LCS(x,y) SA1.que(n-y+1,n-x+1)
     7 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     8 typedef long long ll;
     9 using namespace std;
    10 
    11 const int N=60010;
    12 int n,T,f[N],g[N],log[N];
    13 char s[N]; ll ans;
    14 
    15 struct Suffix{
    16     int lst,cnt,np,tot,h[N],pos[N],x[N],b[N],mx[N];
    17     int son[N][27],fa[N],ch[N][27],rk[N],sa[N],st[N][16];
    18     void init(){ lst=cnt=1; tot=0; mem(b); mem(ch); mem(fa); mem(son); }
    19     
    20     void ext(int c,int k){
    21         int p=lst; lst=np=++cnt; pos[np]=k; b[np]=1; mx[np]=mx[p]+1;
    22         while (p && !son[p][c]) son[p][c]=np,p=fa[p];
    23         if (!p) fa[np]=1;
    24         else{
    25             int q=son[p][c];
    26             if (mx[q]==mx[p]+1) fa[np]=q;
    27             else{
    28                 int nq=++cnt; mx[nq]=mx[p]+1; pos[nq]=pos[q];
    29                 while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
    30                 memcpy(son[nq],son[q],sizeof(son[nq]));
    31                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    32             }
    33         }
    34     }
    35 
    36     void build(){ rep(i,2,cnt) ch[fa[i]][x[pos[i]+mx[fa[i]]]]=i; }
    37     void dfs(int x){
    38         if (b[x]) sa[rk[pos[x]]=++tot]=pos[x];
    39         rep(i,1,26) if (ch[x][i]) dfs(ch[x][i]);
    40     }
    41     
    42     void get(){
    43         int k=0;
    44         rep(i,1,n){
    45             for (int j=sa[rk[i]-1]; i+k<=n && j+k<=n && x[i+k]==x[j+k]; k++);
    46             h[rk[i]]=k; if (k) k--;
    47         }
    48     }
    49 
    50     void rmq(){
    51         rep(i,1,n) st[i][0]=h[i];
    52         rep(i,1,log[n])
    53         rep(j,1,n-(1<<i)+1) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
    54     }
    55 
    56     int ask(int l,int r){
    57         l++; int t=log[r-l+1];
    58         return min(st[l][t],st[r-(1<<t)+1][t]);
    59     }
    60 
    61     int que(int x,int y){ return ask(min(rk[x],rk[y]),max(rk[x],rk[y]));}
    62 
    63     void build_sa(char s[]){
    64         for (int i=n; i; i--) ext(x[i]=s[i]-'a'+1,i);
    65         build(); dfs(1); get(); rmq();
    66     }
    67 }SA,SA1;
    68 
    69 void solve(){
    70     mem(f); mem(g);
    71     for (int len=1,x,y,l,r; 2*len<=n; len++)
    72         for (int i=1,j=len+1; j<=n; i+=len,j+=len)
    73             if (s[i]==s[j]){
    74                 x=LCS(i,j); y=LCP(i,j);
    75                 l=max(i,i-x+len); r=min(i+y,j);
    76                 if (r>l){
    77                     f[l+len]++; f[r+len]--;
    78                     g[l-len+1]++; g[r-len+1]--;
    79                 }
    80             }
    81     rep(i,2,n) f[i]+=f[i-1],g[i]+=g[i-1];
    82     rep(i,1,n-1) ans+=(ll)f[i]*g[i+1];
    83 }
    84 
    85 int main(){
    86     freopen("bzoj4650.in","r",stdin);
    87     freopen("bzoj4650.out","w",stdout);
    88     log[1]=0; rep(i,2,N) log[i]=log[i>>1]+1;
    89     scanf("%d",&T);
    90     while (T--){
    91         SA.init(); SA1.init(); scanf("%s",s+1); n=strlen(s+1);
    92         SA.build_sa(s); reverse(s+1,s+n+1);
    93         SA1.build_sa(s); reverse(s+1,s+n+1);
    94         ans=0; solve(); printf("%lld
    ",ans);
    95     }
    96     return 0;
    97 }
  • 相关阅读:
    C# NAudio录音和播放音频文件及实时绘制音频波形图(从音频流数据获取,而非设备获取)
    C# NAudio录音和播放音频文件-实时绘制音频波形图(从音频流数据获取,而非设备获取)
    C# 录音和播放录音-NAudio
    转载:需求分析师和产品经理有什么区别?
    商业分析师
    网络基础概念
    软件需求工程
    微信APP分析报告
    产品经理的工作职责
    如何编写产品分析报告
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9272936.html
Copyright © 2011-2022 走看看