1. 程式人生 > >BZOJ3238: [Ahoi2013]差異(字尾陣列)

BZOJ3238: [Ahoi2013]差異(字尾陣列)

Description

Input

一行,一個字串S

Output

一行,一個整數,表示所求值

Sample Input

cacao

Sample Output

54

解題思路:

看到lcp,想到了height陣列,沒錯,這道題是一道字尾陣列題。

前面那兩項好像可以累和,值為(len-1)*len*(len+1)/2

就剩sigma(lcp)了。

想到了單調棧直接累和發現WA了,非常尷尬。

最後知道好像漏了點什麼,就是說之前的height不可以說彈棧了就要遺棄,那是會漏解的。

要重複累加。也就是用dp陣列來維護貢獻,每次彈棧後累加。

你不會怕我加重吧,可以證明,彈棧只會在一個階段停下,而之前的值在最終貢獻中體現。

程式碼:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long lnt;
 5 int sa[1000000];
 6 int rnk[1000000];
 7 int has[1000000];
 8 int tmr[1000000];
 9 int hgt[1000000];
10 char str[1000000];
11 char ln[1000000];
12 int stack[1000000];
13 lnt dp[1000000
]; 14 int top; 15 int len; 16 int cnt; 17 lnt ans; 18 bool Same(int a,int b,int l) 19 { 20 if(a+l>len||b+l>len) 21 return false; 22 return (rnk[a]==rnk[b])&&(rnk[a+l]==rnk[b+l]); 23 } 24 int main() 25 { 26 scanf("%s",str+1); 27 len=strlen(str+1); 28
for(int i=1;i<=len;i++) 29 has[str[i]]++; 30 for(int i=0;i<128;i++) 31 if(has[i]) 32 tmr[i]=++cnt; 33 for(int i=1;i<128;i++) 34 has[i]+=has[i-1]; 35 for(int i=1;i<=len;i++) 36 { 37 sa[has[str[i]]--]=i; 38 rnk[i]=tmr[str[i]]; 39 } 40 for(int k=1;cnt!=len;k<<=1) 41 { 42 cnt=0; 43 for(int i=0;i<=len;i++) 44 has[i]=0; 45 for(int i=1;i<=len;i++) 46 has[rnk[i]]++; 47 for(int i=1;i<=len;i++) 48 has[i]+=has[i-1]; 49 for(int i=len;i;i--) 50 if(sa[i]>k) 51 tmr[sa[i]-k]=has[rnk[sa[i]-k]]--; 52 for(int i=1;i<=k;i++) 53 tmr[len-i+1]=has[rnk[len-i+1]]--; 54 for(int i=1;i<=len;i++) 55 sa[tmr[i]]=i; 56 for(int i=1;i<=len;i++) 57 if(Same(sa[i],sa[i-1],k)) 58 tmr[sa[i]]=cnt; 59 else 60 tmr[sa[i]]=++cnt; 61 for(int i=1;i<=len;i++) 62 rnk[i]=tmr[i]; 63 } 64 hgt[1]=0; 65 for(int i=1;i<=len;i++) 66 { 67 if(rnk[i]==1) 68 continue; 69 int j=std::max(1,hgt[rnk[i-1]]-1); 70 while(str[i+j-1]==str[sa[rnk[i]-1]+j-1]) 71 hgt[rnk[i]]=j++; 72 } 73 stack[0]=0; 74 for(int i=1;i<=len;i++) 75 { 76 while(top&&hgt[stack[top]]>hgt[i]) 77 top--; 78 dp[i]=(lnt)(i-stack[top])*(lnt)(hgt[i])+dp[stack[top]]; 79 ans+=dp[i]; 80 stack[++top]=i; 81 } 82 ans<<=1; 83 printf("%lld\n",(lnt)(len-1)*(lnt)(len+1)*(lnt)(len)/2-ans); 84 return 0; 85 }