[bzoj4516] [SDOI2016]生成魔咒
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
Sample Output
1
3
6
9
12
17
22
Solution
后缀数组。
把原串\(reverse\)一下,建出后缀数组,求一下\(height\)数组。
然后按后缀的字典序建一个链表,每次考虑把串第一个位置的后缀算出贡献,然后利用链表合并一下\(height\)就好了。
最后倒序前缀和输出答案就行了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 1e6+10;
const int inf = 1e9;
int n,w[maxn],r[maxn];
int spx[maxn],spy[maxn],sum[maxn],sa[maxn],rk[maxn],height[maxn],d[maxn][20],lg[maxn];
void build() {
int m=n,p=0;int *x=spx,*y=spy;
for(int i=1;i<=n;i++) sum[x[i]=w[i]]++;
for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
for(int i=n;i;i--) sa[sum[x[i]]--]=i;
for(int k=1,tot=0;p<n;k<<=1,tot=0) {
for(int i=n-k+1;i<=n;i++) y[++tot]=i;
for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
for(int i=1;i<=m;i++) sum[i]=0;
for(int i=1;i<=n;i++) sum[x[y[i]]]++;
for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
swap(x,y),x[sa[1]]=p=1;
for(int i=2;i<=n;i++)
if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
else x[sa[i]]=p;
m=p;
}
for(int i=1;i<=n;i++) rk[sa[i]]=i;p=1;
for(int i=1;i<=n;i++) {
if(p) p--;
while(w[i+p]==w[sa[rk[i]-1]+p]) p++;
height[rk[i]]=p;
}
}
ll tmp[maxn];
int pre[maxn],nxt[maxn];
int main() {
read(n);for(int i=1;i<=n;i++) read(w[i]),r[i]=w[i];
sort(r+1,r+n+1);int M=unique(r+1,r+n+1)-r-1;
for(int i=1;i<=n;i++) w[i]=lower_bound(r+1,r+M+1,w[i])-r;
reverse(w+1,w+n+1);
build();
for(int i=1;i<n;i++) nxt[i]=i+1;
for(int i=2;i<=n;i++) pre[i]=i-1;
for(int i=1;i<=n;i++) {
int x=rk[i];
int mn=max(height[x],height[nxt[x]]);
tmp[i]=n-i+1-mn;
height[nxt[x]]=min(height[nxt[x]],height[x]);
height[x]=0;
pre[nxt[x]]=pre[x];
if(x) nxt[pre[x]]=nxt[x];
}
reverse(tmp+1,tmp+n+1);
for(int i=1;i<=n;i++) tmp[i]+=tmp[i-1],write(tmp[i]);
return 0;
}