E. Prefix Sum
Time Limit : 6000/3000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 115 Accepted Submission(s) : 30
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
For example, string bc is a suffix string of abc. but ab is not.
A string v is a prefix string of a string w if string v can read from the beginning of string w.
For example, string ab is prefix string of string abc, but bc and abcd are not.
For 2 strings s1 and s2, if there is a string s3 is both the prefix of s1 and s2, we call s3 is a common prefix of s1 and s2.
The longest common prefix of 2 strings is the longest common prefix string of all the common prefix strings among these 2 strings.
Your task is:
Give you the string, count the sum of the length of each of the longest common prefix string of each 2 suffix of the string.
Input
Output
Sample Input
ABC ABABA AABB
Sample Output
0 7 2
Author
Source
這題是校賽兩題放AK的題之一,題意是求一個字符串的所有後綴之間的最長前綴的總和,當時敲好後綴數組模板後發現我想錯了,當時最優的想也是O(n^2),會tle,好像剪剪就能過去了,今天剪過去了,400+ms,正解是單調棧處理,當時不會做,比賽後想了很久都不知道單調棧要怎麼操作,今天切dp的時候發現了dp可以解這類單調棧的問題,就是一個很簡單的轉移,方法近乎O(n),100+ms過了,好快,如果用dc3可能更快,轉移的重點
for(int i=len;i>=0;i--)
{
while(d[i]<len&&height[i]<=height[d[i]+1])
d[i]=d[d[i]+1];
}
這個轉好像有兩個for,其實複雜度幾乎O(n),標記這個height值可以到最右邊的位置,這樣我們每次統計就可以用一段來統計,中間跳轉,速度很快。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#define LG long long
#define FOR(i,a,n) for(int i=a;i<n;++i)
#define REP(i,n) FOR(i,0,n)
using namespace std;
#define maxn 200002
int wa[maxn],wb[maxn],wv[maxn],wc[maxn];
int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa,int n,int m)
{
int *x=wa,*y=wb,*t;
REP(i,m) wc[i]=0;
REP(i,n) wc[x[i]=r[i]]++;
FOR(i,1,m) wc[i]+=wc[i-1];
for(int i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
for(int j=1,p=1;p<n;j*=2,m=p)
{
p=0;
for(int i=n-j;i<n;i++) y[p++]=i;
REP(i,n) if(sa[i]>=j) y[p++]=sa[i]-j;
REP(i,n) wv[i]=x[y[i]];
REP(i,m) wc[i]=0;
REP(i,n) wc[wv[i]]++;
FOR(i,1,m) wc[i]+=wc[i-1];
for(int i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
swap(x,y);
p=1,x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]] = cmp( y, sa[i-1], sa[i], j)?p-1:p++;
}
return;
}
int rk[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rk[sa[i]]=i;
for(i=0;i<n;height[rk[i++]]=k)
for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
return;
}
char s[maxn];
int r[maxn],sa[maxn],h[maxn],d[maxn];
int main()
{
while(~scanf("%s",s))
{
int len=strlen(s);
for(int i=0;i<len;i++)
{
r[i]=s[i];
d[i]=i;
}
d[len]=len;
r[len]=0;
da(r,sa,len+1,256);
calheight(r,sa,len);
int ans=0;
for(int i=len;i>=0;i--)
{
while(d[i]<len&&height[i]<=height[d[i]+1])
d[i]=d[d[i]+1];
}
for(int i=0;i<=len;i++)
{
if(height[i]==0)continue;
int bin=i,flag=i;
while(bin<=len)
{
ans+=height[bin]*(d[bin]-flag+1);
flag=bin=d[bin]+1;
}
}
printf("%d\n",ans);
}
return 0;
}