您的位置:首页 > 其它

后缀数组+单调栈 【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、单调栈第一个弹栈的判断条件打”>=”,第二个要打”>”,否则会重复计算出错。

代码如下:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  后缀数组 单调栈