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; }