• AHOI2013 差异 【后缀数组】


    题目分析:

    求出height以后很明显跨越最小height的一定贡献是最小height,所以对于区间找出最小height再将区间对半分。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 502000;
     5 const int N = 500000;
     6 
     7 int n;
     8 char str[maxn];
     9 
    10 int sa[maxn],rk[maxn],X[maxn],Y[maxn];
    11 int height[maxn],h[maxn],RMQ[maxn][20],pos[maxn][20];
    12 
    13 int chk(int x,int k){
    14     return rk[sa[x]]==rk[sa[x-1]]&&rk[sa[x]+(1<<k)]==rk[sa[x-1]+(1<<k)];
    15 }
    16 
    17 void getsa(){
    18     for(int i=0;i<n;i++) X[str[i]]++;
    19     for(int i=1;i<=N;i++) X[i] += X[i-1];
    20     for(int i=n-1;i>=0;i--) sa[X[str[i]]--] = i;
    21     for(int i = 2, num = 1;i <= n;i++)
    22     rk[sa[i]] = (str[sa[i]] == str[sa[i-1]]?num:++num);
    23     rk[sa[1]] = 1;
    24     for(int k=1;(1<<k-1)<=n;k++){
    25     for(int i=1;i<=N;i++) X[i] = 0;
    26     for(int i=n-(1<<k-1);i<n;i++) Y[i-n+(1<<k-1)+1]=i;
    27     for(int i=1,j=(1<<k-1)+1;i<=n;i++)
    28         if(sa[i]>=(1<<k-1))Y[j++]=sa[i]-(1<<k-1);
    29     for(int i=0;i<n;i++) X[rk[i]]++;
    30     for(int i=1;i<=N;i++) X[i]+=X[i-1];
    31     for(int i=n;i>=1;i--) sa[X[rk[Y[i]]]--] = Y[i];
    32     int num = 1; Y[sa[1]] = 1;
    33     for(int i=2;i<=n;i++) Y[sa[i]] = (chk(i,k-1)?num:++num);
    34     for(int i=0;i<n;i++) rk[i] = Y[i];
    35     if(num == n) break;
    36     }
    37 }
    38 void getheight(){
    39     for(int i=0;i<n;i++){
    40     if(i) h[i] = max(0,h[i-1]-1); else h[i] = 0;
    41     if(rk[i] == 1) continue;
    42     int comp = sa[rk[i]-1];
    43     while(str[comp+h[i]] == str[i+h[i]])h[i]++;
    44     }
    45     for(int i=0;i<n;i++) height[rk[i]] = h[i];
    46     for(int i=1;i<=n;i++) RMQ[i][0] = height[i],pos[i][0] = i;
    47     for(int k=1;(1<<k)<=n;k++){
    48     for(int i=1;i<=n;i++){
    49         if(i+(1<<k-1)>n) RMQ[i][k]=RMQ[i][k-1],pos[i][k]=pos[i][k-1];
    50         else {
    51         if(RMQ[i][k-1]<RMQ[i+(1<<k-1)][k-1]) pos[i][k] = pos[i][k-1];
    52         else pos[i][k] = pos[i+(1<<k-1)][k-1];
    53         RMQ[i][k] = min(RMQ[i][k-1],RMQ[i+(1<<k-1)][k-1]);
    54         }
    55     }
    56     }
    57 }
    58 int getLCP(int L,int R){
    59     if(L > R) swap(L,R);
    60     if(L == R) return n-sa[L];
    61     L++;
    62     int k = 0; while((1<<k+1)<=R-L+1)k++;
    63     if(RMQ[L][k]<RMQ[R-(1<<k)+1][k]) return pos[L][k];
    64     else return pos[R-(1<<k)+1][k];
    65 }
    66 
    67 long long ans = 0;
    68 
    69 void divide(int l,int r){
    70     if(l == r) return;
    71     int ps = getLCP(l,r);
    72     ans -= 2ll*(ps-l)*(r-ps+1)*height[ps];
    73     divide(l,ps-1); divide(ps,r);
    74 }
    75 
    76 void work(){
    77     n = strlen(str);
    78     getsa();
    79     getheight();
    80     for(int i=1;i<=n;i++) ans += 1ll*i*i-i;
    81     for(int i=1;i<=n;i++) ans += 1ll*i*(n-i);
    82     divide(1,n);
    83     printf("%lld
    ",ans);
    84 }
    85 
    86 int main(){
    87     scanf("%s",str);
    88     work();
    89     return 0;
    90 }
  • 相关阅读:
    40. 组合总和 II(回溯法)
    39. 组合总和(回溯法)
    1640. 能否连接形成数组
    890. 查找和替换模式
    386. 字典序排数
    20. 有效的括号
    496. 下一个更大元素 I
    115. 不同的子序列
    59. 螺旋矩阵 II
    HTML基本结构,标签
  • 原文地址:https://www.cnblogs.com/Menhera/p/10065153.html
Copyright © 2020-2023  润新知