#2033. 「SDOI2016」生成魔咒(广义SAM)
题意:求字符串所有前缀的本质不同的字符串个数 。
此题唯一的亮点是:字符集 较大,因为是每个字符是数字,所以考虑用 存,然后每次插入字符后,更新并输出答案即可, 。
另外此题还可以跑拓扑或者 状态转移。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=8e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false),cin.tie(0)
int n,q,tot,num;
char s[N];
map<int,int>mp;
struct SAM{
int last,cnt;map<int,int>ch[N];
int fa[N],len[N];
ll ans=0;
void insert(int c){
int p=last,np=++cnt;last=np;len[np]=len[p]+1;
for(;p&&!ch[p].count(c);p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else {
int nq=++cnt;len[nq]=len[p]+1;
ch[nq]=ch[q];
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
ans+=len[np]-len[fa[np]];//重要.
}
void build(){
last=cnt=1;
int n,x;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(!mp[x]) mp[x]=++num;
insert(mp[x]);
printf("%lld\n",ans);
}
}
}sam;
int main(){
sam.build();
return 0;
}