JZOJ.5315【NOIP2017模拟8.19】小串串

Description

 

Input

Output

 

Sample Input

4
aa
abcd
ccc
abcc

Sample Output

5
10
14
12
 

Data Constraint

字符串操作我们可以采用任何后缀的东西,包括后缀数组,后缀自动机,后缀树等等...

鉴于某蒟蒻只会后缀数组下面我们采用后缀数组的方法

本题要求出某字符子串在原串出现的次数,我们对原串求出height数组后,将height[i]值作为纵坐标,横坐标为i我们可以发现

矩形宽度即为某子串出现的次数,高度为该串的长度,每个单位高度的矩形就对答案贡献宽度的平方值,于是我们用单调栈来统计这矩形对答案的贡献,然后剩下的子串对答案都贡献1即可。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define N 100005
 8 using namespace std;
 9 long long t,n,sa[N],rank[N],tp[N],tax[N],h[N],len,a[N],top,id[N],sum,m,ans,oo[N];
10 char qwq[N];
11 void rsort(){
12     for (int i=1;i<=m;i++) tax[i]=0;
13     for (int i=1;i<=len;i++) tax[rank[tp[i]]]++;
14     for (int i=1;i<=m;i++) tax[i]+=tax[i-1];
15     for (int i=len;i>=1;i--) sa[tax[rank[tp[i]]]--]=tp[i];
16 }
17 bool comp(long long *f,int x,int y,int w){
18     return ((f[x]==f[y])&&(f[x+w]==f[y+w]));
19 }
20 void SS(){
21     for (int i=1;i<=len;i++) rank[i]=a[i],tp[i]=i;
22     m=128;rsort();
23     for (int i,p=1,w=1;p<len;w+=w,m=p){
24         for (p=0,i=len-w+1;i<=len;i++) tp[++p]=i;
25         for (i=1;i<=len;i++) if (sa[i]>w) tp[++p]=sa[i]-w;
26         rsort();swap(tp,rank);rank[sa[1]]=1;p=1;
27     for (i=2;i<=len;i++) rank[sa[i]]=comp(tp,sa[i],sa[i-1],w)?p:++p;
28     }
29     int j=0,k=0;
30     for (int i=1;i<=len;oo[rank[i++]]=k)
31      for (k=k?k-1:k,j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
32 }
33 void work(){
34     long long tmp=0;
35     for (long long i=1;i<=len;i++){
36         while ((h[id[top]]>=h[i])&&(top>0)){
37             long long x=i-id[top-1];
38             long long y=h[id[top]]-max(h[id[top-1]],h[i]);
39             ans+=x*x*y;
40             sum+=x*y;
41             top--;
42         }
43         id[++top]=i;
44     }
45     ans+=(n-sum);
46     printf("%lld\n",ans);
47 }
48 void clear(){
49     memset(sa,0,sizeof(sa));
50     memset(rank,0,sizeof(rank));
51     memset(h,0,sizeof(h));
52     memset(id,0,sizeof(id));
53     memset(a,0,sizeof(a));
54     top=0;
55     ans=0;
56     sum=0;
57     len=0;
58     n=0;
59 }
60 int main(){
61     for (scanf("%lld",&t);t;t--){
62         scanf("%s",qwq);
63         n=strlen(qwq);
64         for (int i=0;i<n;i++)
65             a[i+1]=(long long)qwq[i]-(long long)'a'+1;
66         len=n;
67         n=n*(n+1)/2;
68         SS();
69         for (int i=1;i<=len;i++)
70          h[i]=oo[i+1];
71         work();
72         clear();
73     }
74     return 0;
75 }
神奇的代码

第一次打单调栈打到崩溃QAQ

posted @ 2017-08-20 16:49  ~Lanly~  阅读(216)  评论(0编辑  收藏  举报