BZOJ4516:[Sdoi2016]生成魔咒
4516: [Sdoi2016]生成魔咒
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1121 Solved: 623
[Submit][Status][Discuss]
Description
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、
[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都
需要求出,当前的魔咒串 S 共有多少种生成魔咒。
Input
第一行一个整数 n。
第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。
1≤n≤100000。,用来表示魔咒字符的数字 x 满足 1≤x≤10^9
Output
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
Sample Input
7
1 2 3 3 3 1 2
1 2 3 3 3 1 2
Sample Output
1
3
6
9
12
17
22
3
6
9
12
17
22
思路{
我们可以轻松求出插入之后的本质不同的子串个数。
怎么乱搞呢?
我们从后往前考虑:{
加入一个数就是加入一个后缀:那我们直接统计这个后缀的贡献值都可以了。
在非动态的情况下,每一个的贡献是n-height[i]+1;
在动态的情况下,那每个的贡献就是(n-(rnk的前驱或后继)的LCP最大值+1);
那我们用set或treap或Splay维护一下即可。
}
}
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define il inline
#define RG register
#define db double
#define LL long long
#define maxx 100010
using namespace std;
set<LL> q;
set<LL>::iterator it;
LL a[maxx],tong[maxx],X[maxx],Y[maxx],height[maxx],rnk[maxx],f[maxx][19],pre[maxx],nxt[maxx],ans[maxx],sa[maxx];
il bool comp(LL *r,LL a,LL b,LL len){return r[a]==r[b]&&r[len+b]==r[len+a];}
il void build_sa(LL n){
LL *x=X,*y=Y,*t,Max=maxx-1;
for(RG LL i=0;i<n;++i)tong[x[i]=a[i]]++;
for(RG LL i=1;i<=Max;++i)tong[i]+=tong[i-1];
for(RG LL i=n-1;i!=-1;i--)sa[--tong[x[i]]]=i;
for(RG LL j=1,i,p=0;p<n;j<<=1,Max=p){
for(i=n-1,p=0;i>=n-j;--i)y[p++]=i;
for(i=0;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<=Max;++i)tong[i]=0;
for(i=0;i<n;++i)tong[x[y[i]]]++;
for(i=1;i<=Max;++i)tong[i]+=tong[i-1];
for(i=n-1;i>=0;i--)sa[--tong[x[y[i]]]]=y[i];
for(i=1,p=1,t=x,x=y,y=t,x[sa[0]]=0;i<n;++i)
x[sa[i]]=comp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
LL n;
il void geth(){
RG LL i,j,k=0;
for(i=1;i<=n;++i)rnk[sa[i]]=i;
for(i=0;i<n;height[rnk[i++]]=k)
for((k?k--:0),j=sa[rnk[i]-1];a[j+k]==a[i+k];k++);
}
void RMQ(){
for(int i=1;i<=n;++i)f[i][0]=height[i];
for(int j=1;(1<<j)<=n;++j)
for(int i=1;i+(1<<(j-1))-1<=n;++i)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
LL LCP(int x,int y){
if(x==y)return n-x+1;
x=rnk[x],y=rnk[y];if(x>y)swap(x,y);x++;
int t=(int)(log(double(y-x+1))/log(2.000));
return min(f[x][t],f[y-(1<<t)+1][t]);
}
il void update(LL x,LL y,LL kind){x=sa[x],y=sa[y];if(kind)pre[x]=y;else nxt[x]=y;}
LL sub[maxx];
il void luangao(){
for(int i=0;i<n;++i)sub[i]=a[i];
sort(sub,sub+n); int size=unique(sub,sub+n)-sub;
for(int i=0;i<n;i++)
a[i]=lower_bound(sub,sub+size,a[i])-sub+1;
}
il void work(){
scanf("%lld",&n);
for(RG LL i=n-1;i!=-1;--i)scanf("%lld",&a[i]);luangao();
a[n]=0;build_sa(n+1),geth();RMQ();
for(RG LL i=n-1;i!=-1;i--){
bool flag1=false,flag2=false;
q.insert(rnk[i]),it=q.find(rnk[i]);
if(it!=q.begin())it--,update(rnk[i],*it,1),it++,flag1=true;
if((++it)!=q.end())update(rnk[i],*it,0),flag2=true;
LL now=n-i,lcp=0;if(flag1)lcp=LCP(i,pre[i]);
if(flag2)lcp=max(lcp,LCP(i,nxt[i]));
ans[now]=now-lcp+ans[now-1];
}for(RG LL i=1;i<=n;++i)cout<<ans[i]<<"\n";
}
int main(){
freopen("menci_incantation.in","r",stdin);
freopen("menci_incantation.out","w",stdout);
work();return 0;
}

浙公网安备 33010602011771号