【文文殿下】 [SDOI2016]生成魔咒
阿新 • • 發佈:2018-11-22
字符集大小為1e9.............使用 map 吧
統計本質不同的子串個數是SAM的經典應用之一
本質不同的子串個數其實就是\(\sum max(x)-min(x)+1\)
所以我們新建結點 \(np\) 時統計它的答案即可
根據我們統計的式子,顯然新建節點\(nq\)的時候,不會對答案造成影響。
#include<cstdio> #include<cstring> #include<map> typedef long long ll; const int maxn = 2e5+20; int par[maxn],mx[maxn],tr[maxn][26],Right[maxn],c[maxn],id[maxn]; char A[maxn>>1]; int tot=0; std::map<int,int> M; int cnt = 1,last = 1; ll ans = 0; void extend(int x) { int np = ++cnt,p = last; Right[np]=1; mx[np]=mx[p]+1; last=np; while(p&&!tr[p][x]) tr[p][x]=np,p=par[p]; if(!p) par[np]=1; else { int q = tr[p][x]; if(mx[q]==mx[p]+1) { par[np]=q; } else { int nq = ++cnt; mx[nq]=mx[p]+1; memcpy(tr[nq],tr[q],sizeof tr[nq]); par[nq]=par[q]; par[q]=par[np]=nq; while(p&&tr[p][x]==q) tr[p][x]=nq,p=par[p]; } } ans+=mx[np]-mx[par[np]]; return; } int n,k,t; inline void topsort() { for(int i = 1;i<=cnt;++i) ++c[mx[i]]; for(int i = 1;i<=n;++i) mx[i]+=mx[i-1]; for(int i = 1;i<=cnt;++i) id[c[mx[i]]--]=i; for(int i = cnt;i;--i) Right[par[id[i]]]+=Right[id[i]]; return; } int ch; int main() { scanf("%d",&n); for(int i = 1;i<=n;++i) { scanf("%d",&ch); if(M[ch]==0) { M[ch]=++tot; } extend(M[ch]); printf("%lld\n",ans); } return 0; }