SDOI2016 生成魔咒

2022-03-27 07:51:59 字數 1616 閱讀 8725

這是一道\(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 不就得了。嘴角再次上揚。寫完過...