這是一道\(sa\)的練手好題
建議做之前先去做一下2408
之後你就肯定會做這道題了
首先上面那道題的答案就是
\[\sum_^nn+1-sa[i]-het[i]
\]就是對於每乙個字尾求出其能產生的子串,之後減掉和之前本質相同的子串
對於這個題,我們需要求出所有字首的本質不同的子串個數
先無腦敲上\(sa\)和\(het\)的板子,之後我們只需要往裡面動態新增字尾就好了
但是如果正著處理的話會有乙個非常顯然的問題,也就是我們加進去乙個字尾,但是這個字尾和之前的一些字尾形成的\(lcp\)長度超過當前的長度,會導致我們很難計算
所以我們需要把字串倒過來,之後每次往裡面新增乙個字尾就只相當於往裡面新增了乙個字元
反置字串顯然不會令子串變得不相等,於是我們可以完美解決這個問題
之後我們維護上面的那個柿子就好了,由於我們插入的\(sa\)值並不連續,所以我們不能直接用\(het\),而是\(het\)的最小值
於是我們用乙個\(st\)表來查詢\(het\)的最小值,之後每插入乙個點相當於要斷裂乙個原來存在的排名連續的字尾,所以還需要乙個\(set\)來找前驅和後繼
**
#include#include#include#include#include#define re register
#define ll long long
#define maxn 100005
#define set_it std::set::iterator
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
int a[maxn],rk[maxn],tp[maxn],tax[maxn],sa[maxn],het[maxn],b[maxn],to[maxn];
int st[maxn][18],log_2[maxn];
int n,m,sz;ll ans=1;
std::sets;
inline void qsort()
inline int pre(int x)
inline int nxt(int x)
inline int find(int x)
int k=0;
for(re int i=1;i<=n;i++)
for(re int i=2;i<=n;i++) log_2[i]=1+log_2[i>>1];
for(re int i=1;i<=n;i++) st[i][0]=het[i];
for(re int j=1;j<=17;j++)
for(re int i=1;i+(1
for(re int i=n-1;i;--i)
x=nxt(rk[i]);
if(x!=-1) to[rk[i]]=ask(rk[i]+1,x),ans-=to[rk[i]];
printf("%lld\n",ans);
} return 0;
}
SDOI2016 生成魔咒
魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 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...
SDOI2016 生成魔咒
魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 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...
SDOI2016 生成魔咒(字尾自動機)
看一眼題。本質不同的字串數。嘴角微微上揚。每一次加乙個數輸出乙個答案。笑容漸漸消失。等等,sam 好像也可以求本質不同的字串。設當前字串用 x 表示,每次插入完成後 ans 加上 len x len fa 就行了。嘴角微微上揚。等等,炸空間了。笑容漸漸消失。用 map 不就得了。嘴角再次上揚。寫完過...