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 }

 

posted @ 2018-11-24 22:53  Unstoppable728  阅读(184)  评论(0编辑  收藏  举报