bzoj4516 Sdoi2016 生成魔咒

2021-07-23 03:36:17 字數 2815 閱讀 9721

4516: [sdoi2016]生成魔咒

time limit: 

10 sec  

memory limit: 

128 mb

submit: 

575  

solved: 

327[

submit

][status

][discuss

]魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 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,1,1] 三種。最初 s 為空串。共進行 n 次操作,每次操作是在 s 的結尾加入乙個魔咒字元。每次操作後都

需要求出,當前的魔咒串 s 共有多少種生成魔咒。

第一行乙個整數 n。

第二行 n 個數,第 i 個數表示第 i 次操作加入的魔咒字元。

1≤n≤100000。,用來表示魔咒字元的數字 x 滿足 1≤x≤10^9

輸出 n 行,每行乙個數。第 i 行的數表示第 i 次操作後 s 的生成魔咒數量

71 2 3 3 3 1 213

691217

22題目是讓你回答每個字首i中出現了多少種本質不同的字串。

有一種演算法是求解整個字串中出現了多少不同的字串,這個在羅穗騫的《字尾陣列——處理字串的有力工具》中出現過,就是從上往下掃瞄height陣列,每次給答案累加sa[i]+1-height[i],也就是這個串和前面的串不同的字首的數目。

設想一:用上面說的方法掃瞄,令f[i]表示以第i個字元為結尾的本質不同的子串的數目,那麼最後f陣列的前i項和就是以i為結尾的本質不同的字串的個數。統計方法:對於每個字串,給f[sa[i]+height[i]]到f[n]加1,用樹狀陣列優化到nlogn

推翻設想一:上面的演算法保證了每個本質不同的子串都僅被統計一次,所以最後一項的答案一定是正確的,但其它項的答案可能是不正確的,舉個例子,假如後最排序後有這樣的幾個相鄰項:

ab........

abc....(這個串位置比較靠後)

abcde.....(這個串位置比較靠前)

那麼abc這個串被加到了比較靠後的位置,而比較靠前的位置中就沒有記錄它的資訊,因此abc雖然在比較靠前的位置出現了,但答案中沒有記錄,所以前面的答案就是錯誤的。

問題來了,乙個串如何只被統計在它最早出現的串中。

設想二:改變掃瞄的順序,從長度最長的字尾開始(也就是開頭最靠前的字尾),把它所有的字首都統計一下,加到對應的f陣列裡;然後再做次長的字尾,把它和最長字尾取一下最長公共字首,那麼除了最長公共字首之外的字首就都是新出現的子串,把那些子串加到f陣列對應的位置上;............;第i長的字尾,要和比它長的所有後取一下最長公共字首(取其中的最大值),新出現的字首進行統計......以此反覆。初步的時間複雜度,求sa+st表+和前面所有的取最長公共字首,即o(nlogn+n^2)

設想二的正確性:每個子串在第一次出現時,都被統計到了對應的位置上,且由於我們減去了最長公共字首,每個子串不會被重複統計,也就是說,我們成功地把每個串統計在了它的第一次出現位置上

進一步優化:複雜度主要高在「與所有比它長的串取最長公共字首」上。不難想出,最長公共字首在字尾陣列中是向上、向下都單調不上公升的,因此我們並沒有必要跟所有比它唱的串都取最長公共字首,只需向上、向下分別找第乙個長度比它長的,取一下這中間所有height的最小值就好了。我們維護乙個單調棧,長度單調遞減。具體怎麼弄就不說了,不是重點,反正正著做一遍、再反著做一遍就行了,最終的時間複雜度o(nlogn+n),如果字尾陣列用o(n)的預處理,複雜度將變成o(n),已經是最好的演算法了

runid

user

problem

result

memory

time

language

code_length

submit_time

1645958

710395641

4516

accepted

12564 kb

676 ms

c++/edit

2352 b

2016-09-25 13:40:54

//bzoj4516: [sdoi2016]生成魔咒 字尾陣列

#include #include #include #include #define maxn 100050

#define lowbit(x) (x&-x)

using namespace std;

int sa[maxn], rank[maxn], height[maxn], wa[maxn], wb[maxn], ws[maxn],

wv[maxn], n, m, x[maxn], delt[maxn], tmp[maxn], st[maxn][18],

stack[maxn], top, f[maxn];

long long ans;

maphash;

bool cmp(int *r, int a, int b, int l)

void build_sa(int *r, int *sa, int n, int m)

for(i=1;i<=n;i++)delt[sa[i]+f[i]]++;

}int main()

bzoj4516 SDOI2016 生成魔咒

time limit 10 sec memory limit 128 mb submit 376 solved 232 submit status discuss 魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 1 2 拼湊起來形成乙個魔咒串 1,2 乙個魔咒串 s 的非空字串...

bzoj 4516 Sdoi2016 生成魔咒

time limit 10 sec memory limit 128 mb submit 1026 solved 576 submit status discuss 魔咒串由許多魔咒字元組成,魔咒字元可以用數字表示。例如可以將魔咒字元 1 2 拼湊起來形成乙個魔咒串 1,2 乙個魔咒串 s 的非空字...

BZOJ4516 Sdoi2016 生成魔咒

bzoj4516 每次在結尾新增乙個數,相當於新增乙個字首。那麼倒過來看,變成每次在開頭新增乙個數,也就是新增乙個字尾。假若新的字尾長為 x 那麼相當於在原有的基礎上增加了 x個串,假設其中有 y 個串已經出現過。那麼a nsi ansi 1 x y考慮如何求這個y 考慮新加入的串和已有串的衝突。假...