bzoj 3238: [Ahoi2013]差异

一看字符串 最长公共前缀,用后缀数组+单调栈搞搞就行啦。一定要注意long long 啊

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<queue>
 7 #include<algorithm>
 8 #include<vector>
 9 #define M 2000009
10 #define EPS 1e-10
11 #define MO 19650827
12 #define ll long long
13 using namespace std;
14 ll read()
15 {
16     char ch=getchar();
17     ll x=0,f=1;
18     for(;ch<'0'||ch>'9';ch=getchar())
19         if(ch=='-')
20           f=-1;
21     for(;ch>='0'&&ch<='9';ch=getchar())
22         x=x*10+ch-'0';
23     return x*f;
24 }
25 char ch[M];
26 int K,sa[2][M],rk[2][M],v[M],a[M],p=1,q,n,H[M],t;
27 ll ans,b[M],c[M];
28 void work(int sa[M],int rk[M],int SA[M],int RK[M])
29 {
30   for(int i=1;i<=n;i++)
31     v[rk[sa[i]]]=i;
32   for(int i=n;i;i--)
33     if(sa[i]>K)
34       SA[v[rk[sa[i]-K]]--]=sa[i]-K;
35   for(int i=n-K+1;i<=n;i++)
36     SA[v[rk[i]]--]=i;
37   for(int i=1;i<=n;i++)
38     RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+K]!=rk[SA[i-1]+K]);
39 }
40 int main()
41 {
42    scanf("%s",ch+1);
43    n=strlen(ch+1);
44    for(int i=1;i<=n;i++)
45      a[i]=ch[i]-'a'+1;
46    for(int i=1;i<=n;i++)
47      v[a[i]]++;
48    for(int i=1;i<=26;i++)
49      v[i]+=v[i-1];
50    for(int i=1;i<=n;i++)
51      sa[p][v[a[i]]--]=i;
52    for(int i=1;i<=n;i++)
53      rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]);
54    K=1;
55    for(;K<n;)
56      {
57        work(sa[p],rk[p],sa[q],rk[q]);
58        swap(p,q);
59        K<<=1;
60      }
61    K=0;
62    for(int i=1;i<=n;i++)
63      if(rk[p][i]==1)
64        H[i]=0;
65      else
66        {
67          int j=sa[p][rk[p][i]-1];
68          for(;a[i+K]==a[j+K];K++);
69          H[i]=K;
70          if(K)
71            K--;
72        }
73    ll su=0;
74    for(int i=n-1;i;i--)
75      {
76         ll a1=H[sa[p][i+1]],s=1;
77         for(;b[t]>a1;)
78           {
79             s+=c[t];
80             su-=b[t]*c[t];
81             t--;
82            }
83         su+=a1*s;
84         if(b[t]==a1)
85           c[t]+=s;
86         else 
87           {
88             b[++t]=a1;
89             c[t]=s;
90           }
91         ans+=su;
92      }
93    printf("%lld\n",(ll)(n-1)*n*(n+1)/2-2*ans);
94    return 0;
95 }
96 

 

posted @ 2016-07-07 22:02  xiw5  阅读(144)  评论(0编辑  收藏  举报