bzoj3238 [Ahoi2013]差异
2018-02-19 01:51
423 查看
http://www.elijahqi.win/2018/02/19/bzoj3238/
Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
学农之前想做的题来着的当时怎么也想不明白现在就好一些了
首先看这个式子的前一部分 由于每个字符串恰好出现了n-1次 所以 答案是
(n-1)∑len[i]=(n-1)*n(n+1)/2。 那么显然可以o1求出 那么后面的怎么办 一个显然的方法是暴力枚举o(n^2) 时间复杂度显然难以接受 怎么办 考虑 每个后缀对答案的贡献 每个后缀对答案的贡献一定是这个后缀的height能当最小值的一段区间 大概是前面的个数*后面的个数 那 怎么搞 由于这个顺序并不影响我 我可以单独只考虑height 那么想到 o(n)时间,单调栈求某个点向左能扩展到哪,向右能扩展到哪。两边扩展长度的乘积不就是以该点的值为最小值的区间个数 然后这个最小值乘区间个数就是对答案的贡献 然后最后整体减去这个贡献即可 注意存在height相同的情况 这时候就需要我们更改下判断条件 使得重复的只被计算一次贡献
Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
学农之前想做的题来着的当时怎么也想不明白现在就好一些了
首先看这个式子的前一部分 由于每个字符串恰好出现了n-1次 所以 答案是
(n-1)∑len[i]=(n-1)*n(n+1)/2。 那么显然可以o1求出 那么后面的怎么办 一个显然的方法是暴力枚举o(n^2) 时间复杂度显然难以接受 怎么办 考虑 每个后缀对答案的贡献 每个后缀对答案的贡献一定是这个后缀的height能当最小值的一段区间 大概是前面的个数*后面的个数 那 怎么搞 由于这个顺序并不影响我 我可以单独只考虑height 那么想到 o(n)时间,单调栈求某个点向左能扩展到哪,向右能扩展到哪。两边扩展长度的乘积不就是以该点的值为最小值的区间个数 然后这个最小值乘区间个数就是对答案的贡献 然后最后整体减去这个贡献即可 注意存在height相同的情况 这时候就需要我们更改下判断条件 使得重复的只被计算一次贡献
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define N 550000 using namespace std; int top,q ,n,m,rk1[N<<1],rk[N<<1],height ,sa ,cnt ,tmp ,k,l ,r ; char s ;ll ans; int main(){ freopen("bzoj3238.in","r",stdin); scanf("%s",s+1);n=strlen(s+1); for (int i=1;i<=n;++i) cnt[s[i]]=1; for (int i=1;i<=200;++i) cnt[i]+=cnt[i-1]; for (int i=1;i<=n;++i) rk[i]=cnt[s[i]];m=26; for (int p=1;k!=n;p<<=1,m=k){ for (int i=1;i<=m;++i) cnt[i]=0; for (int i=1;i<=n;++i) ++cnt[rk[i+p]]; for (int i=1;i<=m;++i) cnt[i]+=cnt[i-1]; for (int i=n;i;--i) tmp[cnt[rk[i+p]]--]=i; for (int i=1;i<=m;++i) cnt[i]=0; for (int i=1;i<=n;++i) ++cnt[rk[i]]; for (int i=1;i<=m;++i) cnt[i]+=cnt[i-1]; for (int i=n;i;--i) sa[cnt[rk[tmp[i]]]--]=tmp[i]; memcpy(rk1,rk,sizeof(rk)>>1);rk[sa[1]]=k=1; for (int i=2;i<=n;++i){ if (rk1[sa[i]]!=rk1[sa[i-1]]||rk1[sa[i]+p]!=rk1[sa[i-1]+p]) ++k; rk[sa[i]]=k; } }k=0;ans+=(ll)(n-1)*n*(n+1)>>1; for (int i=1;i<=n;++i){ if (rk[i]==1) continue; k=k==0?0:k-1; while (s[i+k]==s[sa[rk[i]-1]+k]) ++k; height[rk[i]]=k; } for (int i=2;i<=n;++i){ while (top&&height[i]<=height[q[top]]) r[q[top--]]=i-1; q[++top]=i; } while(top) r[q[top--]]=n; for (int i=n;i>=2;--i){ while (top&&height[i]<height[q[top]]) l[q[top--]]=i+1; q[++top]=i; }while(top) l[q[top--]]=2; for (int i=2;i<=n;++i) ans-=2LL*(i-l[i]+1)*(r[i]-i+1)*height[i]; printf("%lld",ans); return 0; }
相关文章推荐
- 【bzoj3238】 Ahoi2013—差异
- BZOJ 3238: [Ahoi2013]差异( 后缀数组 + 单调栈 )
- [BZOJ3238][AHOI2013]差异(SAM)
- BZOJ 3238 [Ahoi2013]差异 后缀数组+单调栈
- [Ahoi2013]差异 bzoj 3238 后缀自动机
- 【BZOJ】【3238】【AHOI2013】diff(差异)
- bzoj3238 [Ahoi2013]差异
- 【BZOJ 3238】[Ahoi2013]差异 后缀自动机构造后缀树
- [bzoj3238][Ahoi2013]差异
- BZOJ 3238 【AHOI2013】 差异
- 【BZOJ】 3238: [Ahoi2013]差异
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
- 【BZOJ】3238: [Ahoi2013]差异
- [BZOJ3238][Ahoi2013][后缀自动机][树形DP]差异
- BZOJ 3238: [Ahoi2013]差异 [后缀自动机]
- bzoj 3238: [Ahoi2013]差异 后缀自动机
- [BZOJ3238][Ahoi2013]差异 做题笔记
- BZOJ3238: [Ahoi2013]差异 (后缀自动机)
- 【bzoj3238】差异[AHOI2013](后缀数组+单调栈)
- 【bzoj3238】[Ahoi2013]差异 后缀数组+单调栈