[JZOJ 1598]文件修复

来源:互联网 发布:快速排序的算法 编辑:程序博客网 时间:2024/05/21 10:23

Description

  有一个文件被破坏了,可是值得庆幸的是,只是文件的顺序被打乱了。文件仅包含大小写的拉丁字母以及逗号,句号和叹号。为了尽快修复,请你找出有多少个至少出现两次的子串。
  比如字符串abbabc,子串”a”,”b”,”ab”分别出现了2次,3次,2次。

Input

  输入文件第一行包含一个整数n表示文件的长度。
  第二行n个字符,表示被破坏的文件。

Output

  输出一个数,表示有多少个至少出现两次的子串。

Sample Input

aabbabb

Sample Output

5

Data Constraint

Hint

【数据约束和评分方法】
  对于10%的数据,1<=n<=100。
  对于30%的数据,1<=n<=1000。
  对于50%的数据,1<=n<=10000。  
  对于100%的数据,1<=n<=100000。


方法什么的挺好想的,用sa求出height之后,假如height[i] - height[i-1] > 0的话,就将差值累加进ans就可以了。
那么为什么要减去前一个的height呢,因为我们对于同一个串,我们只算一遍,所以要减去之前算过的
#include<cstdio>#include<algorithm>#define maxn 100100using namespace std;char ch;int ans,tot,n,ws[maxn],x[maxn],y[maxn],wv[maxn],a[maxn],h[maxn],sa[maxn],t[maxn];bool get(int x){if (x >= 'a' && x <= 'z') return true;if (x >= 'A' && x <= 'Z') return true;if (x == ',' || x == '.' || x == '!') return true;return false;}void init(){while (ch = getchar(),(! get(ch)));a[++ tot] = ch;while (ch = getchar(),(get(ch))) a[++ tot] = ch;n = tot;}bool cmp(int *rank,int a,int b,int l){return (rank[a] == rank[b] && rank[a+l] == rank[b+l]);}void da(int *x,int *y,int *t){int i,j,p,m = 122;for (i = 1 ; i <= m ; i ++) ws[i] = 0;for (i = 1 ; i <= n ; i ++) ws[x[i] = a[i]] ++;for (i = 2 ; i <= m ; i ++) ws[i] += ws[i - 1];for (i = n ; i >= 1 ; i --) sa[ws[x[i]] --] = i;for (j = 1,p = 1 ; p <= n ; j *= 2,m = p){for (p = 0,i = n - j + 1 ; i <= n ; i ++) y[++ p] = i;//!!for (i = 1 ; i <= n ; i ++) if (sa[i] > j) y[++ p] = sa[i] - j;//!!for (i = 1 ; i <= n ; i ++) wv[i] = x[y[i]];for (i = 1 ; i <= m ; i ++) ws[i] = 0;for (i = 1 ; i <= n ; i ++) ws[wv[i]] ++;for (i = 1 ; i <= m ; i ++) ws[i] += ws[i - 1];for (i = n ; i >= 1 ; i --) sa[ws[wv[i]] --] = y[i];for (t = x,x = y,y = t,p = 2,x[sa[1]] = 1,i = 2 ; i <= n ; i ++)x[sa[i]] = cmp(y , sa[i - 1] , sa[i] , j) ? p - 1 : p ++;}}void calc(){int k = 0,j,i;for (i = 1 ; i <= n ; i ++) x[sa[i]] = i;for (i = 1 ; i <= n ; h[x[i ++]] = k)for (k ? k -- : 0,j = sa[x[i] - 1] ; a[i + k] == a[j + k] ; k ++);}void work(){da(x,y,t);calc();for (int i = 1 ; i <= n ; i++) ans += max(h[i] - h[i - 1] , 0);}int main(){init();work();printf("%d",ans);}

0 0
原创粉丝点击