题目:https://www.acwing.com/problem/content/2574/
题意:首先给一个空串s,然后每次往串的后面添加一个数字,问每次添加完后,不同的子串的数量是多少,总共添加n次,所以要输出n行结果。
题解:首先考虑一个固定的串,有多少个不同的子串,因为所有的子串就是所有的后缀的所有前缀,那么求出后缀数组,每一个sa[i]和上面不同前缀的数量就是和前面每一个sa[i-1],sa[i-2],sa[i-3]等等的最大公共前缀,然后用len[i]减去这个值就是答案,然后又因为,这个值其实就是height[i]的值(仔细想想就可以理解),那么其实答案就是所有的len[i]-height[i],考虑添加操作,往后面添加会导致每一个后缀都会改变,又因为,一个串的正序和逆序的不同子串数量是相同的,那么就把这个序列倒过来,变成往前添加,然后添加过程不好操作,可以先把所有信息读入,求出长度为n的后缀数组,然后从小到大删数,每次删数,更改height的信息即可,又因为删掉height[i],更新信息height[i+1]=min(height[i],height[i+1])
#include <bits/stdc++.h>
//#define int long long
#define pb push_back
#define pii pair<int, int>
#define mpr make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
#define x first
#define y second
typedef long long ll;
typedef unsigned long long LL;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
using namespace std;
const int N = 1e6+9;
int n,m;
int s[N];
int sa[N],x[N],y[N],c[N],rk[N],height[N];
int u[N],d[N];//双链表存height关系
ll ans[N];
int get(int x){
static unordered_map<int,int>hash;
if(hash.count(x)==0)hash[x]=++m;
return hash[x];
}
//后缀数组模板
void get_sa(){
for(int i=1;i<=n;i++)c[x[i]=s[i]]++;
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i;i--)sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int num=0;
for(int i=n-k+1;i<=n;i++)y[++num]=i;
for(int i=1;i<=n;i++)
if(sa[i]>k)y[++num]=sa[i]-k;
for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=n;i++)c[x[i]]++;
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y);
x[sa[1]]=1,num=1;
for(int i=2;i<=n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num: ++num;
if(num==n)break;
m=num;
}
}
void get_height(){
for(int i=1;i<=n;i++)rk[sa[i]]=i;
for(int i=1,k=0;i<=n;i++){
if(rk[i]==1)continue;
if(k)k--;
int j=sa[rk[i]-1];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
}
signed main() {
scanf("%d",&n);
for(int i=n;i;i--)scanf("%d",&s[i]),s[i]=get(s[i]);
get_sa();
get_height();
ll res=0;
for(int i=1;i<=n;i++){
res+=n-sa[i]+1-height[i];//得到长度为n的答案
u[i]=i-1,d[i]=i+1;
}
d[0]=1,u[n+1]=n;
for(int i=1;i<=n;i++){
ans[i]=res;
int k=rk[i],j=d[k];
res-=n-sa[k]+1-height[k];//更新答案
res-=n-sa[j]+1-height[j];
height[j]=min(height[j],height[k]);//更新信息
res += n - sa[j] + 1 - height[j]; //更新答案
d[u[k]]=d[k],u[d[k]]=u[k];//双链表删数
}
for(int i=n;i;i--)printf("%lld\n",ans[i]);
return 0;
}