【bzoj3238】【Ahoi2013】差异


  • 题解:

    • 分成两部分来求,$\sum (len(T_{i})+len(T_{j}))$显然是:$\frac{(N-1)N(N+1)}{2}$
    • 另外一部分即所有后缀的$lcp$之和的二倍,枚举每一个$sa[i]$;
    • 这样对于每个j从小到大的$sa[j](j<i)$来说和$sa[i]$的$lcp$是连续的且单调递增,这取决于$j+1$到$i$的$height$最小值;
    • 求出$sa$和$ht$后,用一个单调上升的队列维护每一段的答案;
       1 #include<bits/stdc++.h>
       2 #define ll long long
       3 #define rg register
       4 using namespace std;
       5 const int N=500010;
       6 int len,c[N],x[N],y[N],sa[N],top,st[N],rk[N],ht[N];
       7 ll ans,sum[N];
       8 char s[N]; 
       9 void build_sa(int n,int m){
      10     for(rg int i=0;i<n;i++)c[x[i]=s[i]]++;
      11     for(rg int i=1;i<m;i++)c[i]+=c[i-1];
      12     for(rg int i=n-1;~i;i--)sa[--c[x[i]]]=i;
      13     for(rg int k=1;k<n;k<<=1){
      14         int p = 0;
      15         for(rg int i=n-k;i<n;i++)y[p++]=i;
      16         for(rg int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
      17         for(rg int i=0;i<m;i++)c[i]=0;
      18         for(rg int i=0;i<n;i++)c[x[i]]++;
      19         for(rg int i=1;i<m;i++)c[i]+=c[i-1];
      20         for(rg int i=n-1;~i;i--)sa[--c[x[y[i]]]]=y[i];
      21         swap(x,y);
      22         p=0;x[sa[0]]=p++; 
      23         for(rg int i=1;i<n;i++){
      24             x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p-1 : p++;
      25         }
      26         if(p==n)break;
      27         m = p + 1;
      28     }
      29 }
      30 void build_ht(int n){
      31     for(rg int i=0;i<n;i++)rk[sa[i]]=i;
      32     for(rg int i=0,j,k=0;i<n;i++){
      33         if(k)k--;
      34         j=sa[rk[i]-1];
      35         while(s[i+k]==s[j+k])k++;
      36         ht[rk[i]] = k;
      37     }
      38 }
      39 int main(){
      40     freopen("bzoj3238.in","r",stdin);
      41     freopen("bzoj3238.out","w",stdout);
      42     scanf("%s",s);
      43     len = strlen(s);
      44     ans = (ll)len*(len+1)/2*(len-1);
      45     s[len]='$';
      46     build_sa(len+1,128);
      47     build_ht(len+1);
      48     for(rg int i=0;i<=len;i++){
      49         while(top&&ht[st[top]]>=ht[i])top--;
      50         st[++top]=i;
      51         sum[top] = sum[top-1] + 2ll * (st[top] - st[top-1]) * ht[i];
      52         ans -= sum[top];
      53     }
      54     printf("%lld\n",ans);
      55     return 0;
      56 }
      bzoj3238

猜你喜欢

转载自www.cnblogs.com/Paul-Guderian/p/10222617.html
今日推荐