ZJOI2015陈老师幻想乡的简化(阉割)版,所以可以不用Trie上后缀自动机那么高大上的东西。。。
首先不难想象出O(n^4)以及O(n^2)的做法,一种是每穷举一个字串再暴力检查是否已经出现,一种是在第一种的基础上Hash优化。
这两种都没有什么卵用我们就不提了。
首先我们将数字串反向读入,那么每一个加入的前缀对应反串的一个后缀,我们每加入一个字母,相当于有 该字母开始的后缀和目前已经加入的后缀的最大公共部分重复 ,剩下的就是全新的,用线段树维护区间最大最小即可。
</pre><div class="line number1 index0 alt2" style="font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; line-height: 17.6px; font-size: 16px; border-radius: 0px !important; border: 0px !important; bottom: auto !important; float: none !important; height: auto !important; left: auto !important; margin: 0px !important; outline: 0px !important; overflow: visible !important; padding: 0px 1em !important; position: static !important; right: auto !important; top: auto !important; vertical-align: baseline !important; width: auto !important; box-sizing: content-box !important; min-height: auto !important; white-space: pre !important; background-image: none !important; background-attachment: initial !important; background-size: initial !important; background-origin: initial !important; background-clip: initial !important; background-position: initial !important; background-repeat: initial !important;"><pre name="code" class="cpp">/**************************************************************
Problem: 4516
User: RicardoWang
Language: C++
Result: Accepted
Time:1700 ms
Memory:11824 kb
****************************************************************/
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 100005
void _read(int &x)
{
bool flag=false;char ch=getchar(); x=0;
while(ch<'0'||ch>'9'){if(ch=='-')flag=true; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return ;
}
int a[maxn],b[maxn],n,tot,m;
void Init()
{
_read(n);for(int i=n;i>=1;i--){_read(a[i]);b[i]=a[i];}
sort(b+1,b+1+n);tot=unique(b+1,b+1+n)-b-1;m=tot;
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
return ;
}
int sa[maxn],height[maxn],wa[maxn*2],wb[maxn*2],cc[maxn*2],rank[maxn];
void makesa()
{
int *x=wa,*y=wb,ct,*t;
for(int i=1;i<=m;i++)cc[i]=0;
for(int i=1;i<=n;i++)cc[x[i]=a[i]]++;
for(int i=1;i<=m;i++)cc[i]+=cc[i-1];
for(int i=n;i>=1;i--)sa[cc[x[i]]--]=i;
for(int k=1;k<=n;k=k<<1)
{
ct=0;for(int i=n-k+1;i<=n;i++)y[++ct]=i;
for(int i=1;i<=n;i++)if(sa[i]>k)y[++ct]=sa[i]-k;
for(int i=1;i<=m;i++)cc[i]=0;
for(int i=1;i<=n;i++)cc[x[y[i]]]++;
for(int i=1;i<=m;i++)cc[i]+=cc[i-1];
for(int i=n;i>=1;i--)sa[cc[x[y[i]]]--]=y[i];
t=x;x=y;y=t; x[sa[1]]=1; ct=1;
for(int i=2;i<=n;i++)x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?ct:++ct;
m=ct; if(m>=n)break;
}
return ;
}
void calcheight()
{
int j;
for(int i=1;i<=n;i++)rank[sa[i]]=i;
int k=0;
for(int i=1;i<=n;i++)
{
if(k)k--;
j=sa[rank[i]-1];
while(a[j+k]==a[i+k])k++;
height[rank[i]]=k;
}
return ;
}
int np,rt1,rt2,minv[4*maxn],maxv[4*maxn],chi[4*maxn][2];
void build(int &now,int L,int R ,bool op) //op=false 维护已加入的rank,op==false 维护height
{
now=++np;
if(L==R)
{
if(op)minv[now]=maxv[now]=height[L];
else minv[now]=n+1;maxv[now]=-1;
return ;
}
int m=(L+R)>>1; build(chi[now][0],L,m,op);build(chi[now][1],m+1,R,op);
minv[now]=min(minv[chi[now][0]],minv[chi[now][1]]);
maxv[now]=max(maxv[chi[now][0]],maxv[chi[now][1]]);
return ;
}
void update(int now,int L,int R,int x)
{
if(L==R){minv[now]=maxv[now]=x;return ;}
int m=(L+R)>>1;
if(x<=m)update (chi[now][0],L,m,x); else update(chi[now][1],m+1,R,x);
minv[now]=min(minv[chi[now][0]],minv[chi[now][1]]);
maxv[now]=max(maxv[chi[now][0]],maxv[chi[now][1]]);
return ;
}
int query(int now,int L,int R,int x,int y,bool op)//op==true -> min op==false -> max
{
if(x>y)
{
return op? n+1:-1;
}
if(x<=L && R<=y) return op?minv[now]:maxv[now];
int m=(L+R)>>1;
int t1,t2; t1=t2=op? n+1:-1;
if(x<=m)
{
t1=query(chi[now][0],L,m,x,y,op);
}
if(y>m)
{
t2=query(chi[now][1],m+1,R,x,y,op);
}
return op? min(t1,t2):max(t1,t2);
}
long long ans;
int l,r,t;
char s[35];int cct;
void out(long long x)
{
cct=0; while(x){s[++cct]=x%10+'0';x=x/10;}
while(cct){putchar(s[cct]);cct--;}
putchar('\n');
return ;
}
void work()
{
makesa();
calcheight();
build(rt1,1,n,false);build(rt2,1,n,true);
ans=1;putchar('1');putchar('\n');
update(rt1,1,n,rank[n]);
for(int i=n-1;i>=1;i--)
{
t=-1;
l=query(rt1,1,n,1,rank[i]-1,false);
r=query(rt1,1,n,rank[i]+1,n,true);
if(l<rank[i]&&l>0)t=max(t,query(rt2,1,n,l+1,rank[i],true));
if(r>rank[i]&&r<=n)t=max(t,query(rt2,1,n,rank[i]+1,r,true));
ans+=(long long)((n+1-i)-t);
update(rt1,1,n,rank[i]);
out(ans);
}
return ;
}
int main()
{
//freopen("in.txt","r",stdin);
Init(); work();
return 0;
}