后缀数组+单调栈 【Ahoi2013】bzoj3238 差异
2016-12-28 15:45
351 查看
题目大意:
题目分析:
这个公式的前两项可以提出来单算,这两项的总和应该是(n+1)n/2 (n+2)。
问题就转化成了求任意两个后缀的lcp之和。
我们知道两个后缀的lcp就是height数组取min,那么反过来想,一个位置能影响到的就是自己前面和后面且height值大于当前位置height值的连续的部分(按照个人理解就是以这个位置的lcp当作桥梁,算出一部分lcp的长度), 问题转化为了求左右第一个比自己小的数的位置,单调栈就可以解决这个问题。
注意事项:
1、结果很大会爆int,要用long long来存储和计算最终答案,但是不能全都用long long类型,因为long long运算很慢,会TLE;
2、单调栈第一个弹栈的判断条件打”>=”,第二个要打”>”,否则会重复计算出错。
代码如下:
题目分析:
这个公式的前两项可以提出来单算,这两项的总和应该是(n+1)n/2 (n+2)。
问题就转化成了求任意两个后缀的lcp之和。
我们知道两个后缀的lcp就是height数组取min,那么反过来想,一个位置能影响到的就是自己前面和后面且height值大于当前位置height值的连续的部分(按照个人理解就是以这个位置的lcp当作桥梁,算出一部分lcp的长度), 问题转化为了求左右第一个比自己小的数的位置,单调栈就可以解决这个问题。
注意事项:
1、结果很大会爆int,要用long long来存储和计算最终答案,但是不能全都用long long类型,因为long long运算很慢,会TLE;
2、单调栈第一个弹栈的判断条件打”>=”,第二个要打”>”,否则会重复计算出错。
代码如下:
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<string> #include<cstring> #include<iostream> #define N 1200000 using namespace std; int tot; char s ; int sa ,rnk ,X ,Y ,tmp ,sum ,t,hi ; long long sta ,l ,r ,top; long long ans; void get_rank() { t=0; for(int i=0;i<=127;i++) sum[i]=0; for(int i=1;i<=tot;i++) sum[s[i]]++; for(int i=1;i<=127;i++) sum[i]+=sum[i-1]; for(int i=tot;i>=1;i--) tmp[sum[s[i]]--]=i; for(int i=1;i<=tot;i++) { if(i==1 || s[tmp[i]]!=s[tmp[i-1]]) t++; rnk[tmp[i]]=t; } } void radix_sort(int key[],int order[]) { for(int i=0;i<=tot;i++) sum[i]=0; for(int i=1;i<=tot;i++) sum[key[i]]++; for(int i=1;i<=tot;i++) sum[i]+=sum[i-1]; for(int i=tot;i>=1;i--) tmp[sum[key[order[i]]]--]=order[i]; for(int i=1;i<=tot;i++) order[i]=tmp[i]; } void get_height() { for(int i=1;i<=tot;i++) { if(rnk[i]==1) continue; int j=max(hi[rnk[i-1]]-1,0),k=sa[rnk[i]-1]; while(s[k+j]==s[i+j]) j++; hi[rnk[i]]=j; } } void prefix_array() { get_rank(); for(int j=1;j<=tot;j<<=1) { for(int i=1;i<=tot;i++) { X[i]=rnk[i]; Y[i]=i+j>tot?0:rnk[i+j]; sa[i]=i; } radix_sort(Y,sa); radix_sort(X,sa); t=0; for(int i=1;i<=tot;i++) { if(i==1 || X[sa[i]]!=X[sa[i-1]] || Y[sa[i]]!=Y[sa[i-1]]) t++; rnk[sa[i]]=t; } } get_height(); } int main() { scanf("%s",s+1); tot=strlen(s+1); prefix_array(); top=0; for(int i=1;i<=tot;i++) { while(hi[sta[top]]>=hi[i] && top>0) top--; if(top==0) l[i]=1; else l[i]=sta[top]+1; sta[++top]=i; } top=0; for(int i=tot;i>=1;i--) { while(hi[sta[top]]>hi[i] && top>0) top--; if(top==0) r[i]=tot; else r[i]=sta[top]-1; sta[++top]=i; } long long o=tot; ans=((o+1)*o*(o-1))/2; for(long long i=1;i<=tot;i++) ans-=hi[i]*(r[i]-i+1)*(i-l[i]+1)*2ll; printf("%lld\n",ans); return 0; }
相关文章推荐
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
- BZOJ 3238: [Ahoi2013]差异( 后缀数组 + 单调栈 )
- BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]
- BZOJ.3238.[AHOI2013]差异(后缀自动机 树形DP or 后缀数组 单调栈)
- BZOJ3238 Ahoi2013 差异 后缀自动机,后缀树,后缀数组解法三合一
- BZOJ 3238 [Ahoi2013] 差异 | 后缀数组 单调栈
- bzoj 3238: [Ahoi2013]差异 -- 后缀数组
- bzoj 3238 [Ahoi2013]差异 后缀数组 并查集
- [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】
- BZOJ 3238: [Ahoi2013]差异|后缀数组|乘法原理
- bzoj 3238: [Ahoi2013]差异 后缀数组
- [BZOJ3238][Ahoi2013]差异(后缀数组+单调栈||后缀自动机+树形dp)
- 【bzoj3238】【AHOI2013】【差异】【后缀数组+单调栈】
- 【BZOJ3238】差异(后缀数组,单调栈)
- [bzoj3238][Ahoi2013]差异——后缀自动机
- 【bzoj3238】差异[AHOI2013](后缀数组+单调栈)
- BZOJ 3238 AHOI 2013 差异 后缀数组 单调
- bzoj3238 [Ahoi2013]差异 后缀自动机
- 【bzoj3238】[Ahoi2013]差异 后缀数组+单调栈
- BZOJ 3238 [Ahoi2013]差异 ——后缀自动机