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