LOJ 3103 JSOI2019 節日慶典

2022-05-07 18:42:07 字數 3000 閱讀 5011

給定字串 \(s\) ,對於 \(s\) 的每個字首 \(t\) 求 \(t\) 所有迴圈同構串的字典序最小的串,輸出其起始下標。(如有多個輸出最靠前的)

\(|s| \le 3 \times 10^6\)

本文參考了官方題解。

假設我們現在考慮字首 \(s[1 \dots k]\) ,我們考慮哪些起始位置可能成為答案,我們稱作候選點。也就是對於這些候選點來說,對於 \(i \ge k\) ,他們永遠都會比非候選點更加優秀。

我們首先可以通過不迴圈移位比出他們的字典序的話,肯定可以直接看出哪個一定不是候選點。

性質一:假設兩個位置 \(i < j\) 。 如果 \(\mathrm(s[i \dots n],s[j \dots n]) \le k − j\) , 那麼 \(i,j\) 之間肯定有乙個不是候選點.

讀者自證不難,利用上這個性質才是關鍵。

我們假設得到 \(s[1 \dots k - 1]\) 的候選點集 \(p\) ,對於 \(i, j \in p, i < j\) 那麼一定有 \(\mathrm(s[i \dots n], s[j \dots n]) > (k - 1) - j\) ,我們只需要找出是否存在乙個 \(\mathrm(s[i \dots n],s[j \dots n]) \le k − j\) 即可排除乙個候選點。

我們顯然只需要比較 \(s[i + k - j]\) 與 \(s[k]\) 就能比出來了,但是列舉所有點對是十分浪費的一件事。我們只考慮比較距離最遠兩個元素,留下較優的元素即可。

然後這樣看起來還是 \(\mathcal o(n^2)\) 的,但似乎能跑前 \(50pts\) 。(也許有更嚴謹的更優複雜度吧)

然後還需要利用乙個神奇的性質優化候選點數。

性質二:對於兩個點 \(i < j\) , 假設 \(\mathrm(s[i \dots n],s[j \dots n]]) > k − j\) , 如果有 \(k − j \ge j − i\) , 那麼 \(j\) 不是候選點。

這個性質看上去沒有那麼顯然了。

證明:這個性質是有最小迴圈表示的某個性質得來的, 假設串 \(s = s_1 s_1 s_2\) ,其中 \(s_1, s_2\) 是任意兩個子串。

這個討論 \(s_1, s_2\) 字典序大小不難發現。

那麼如果有 \(k - j \ge j - i\) 那麼 \(s[1 \dots k]\) 形如 \(abbc\) ,那麼我們把這兩個字尾即可用 \(bbca\) 和 \(bcab\) 表示。把 \(s_1\) 設成 \(b\) ,\(s_2\) 設成 \(ca\) ,那麼其實就是 \(s_1s_1s_2\) 與 \(s_1s_2s_1\) ,顯然後者一定會被另外兩個迴圈串包在中間,一定不如其他兩個中的乙個優。

利用上了這個性質,那麼就有相鄰兩個候選點距離翻倍,那麼只有 \(\mathcal o(\log n)\) 個候選點了。

這樣的話,看似我們可以利用各種字尾資料結構在 \(\mathcal o(n \log n)\) 內輕鬆愉悅的解決。

實則不然。。。除非你用 \(\text\) ,那當我沒說。

我們預處理那裡的複雜度要盡量降低,我們還需要知道乙個性質。

性質三:對於任意兩個候選點 \(i < j\) 那麼 \(s[j \dots k]\) 是 \(s[i \dots k]\) 的乙個字首。

這個利用性質一不難發現。

那麼我們發現我們每次其實只需要比較乙個字尾和原串的字典序大小,這正好契合了 \(\mathrm\) 的用途。

不會的話可以看我之前的學習筆記 qwq

然後預處理就變成 \(\mathcal o(n)\) ,總複雜度是 \(\mathcal o(n \log n)\) 。

求區間最小(迴圈)字尾,都可以考慮候選點只有 \(\mathcal o(\log n)\) 個的神奇性質。

#include #define for(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)

#define fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)

#define rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)

#define set(a, v) memset(a, v, sizeof(a))

#define cpy(a, b) memcpy(a, b, sizeof(a))

#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

templateinline bool chkmin(t &a, t b)

templateinline bool chkmax(t &a, t b)

inline int read()

void file()

const int n = 3e6 + 1e3;

void get_next(char *s, int *next) }}

char s[n]; int lcp[n], n; vectorcur;

inline int cmp(int p, int len)

inline int cmp(int x, int y, int len)

int main ()

} cur = tmp; int ans = cur[0];

for (i, 1, cur.size() - 1) ans = cmp(ans, cur[i], k);

printf ("%d%c", ans, k == kend ? '\n' : ' ');

} return 0;

}

Loj 3057 HNOI2019 校園旅行

某學校的每個建築都有乙個獨特的編號。一天你在校園裡無聊,決定在校園內隨意地漫步。你已經在校園裡呆過一段時間,對校園內每個建築的編號非常熟悉,於是你情不自禁的把周圍每個建築的編號都記了下來 但其實你沒有真的記下來,而是把每個建築的編號除以 2 取餘數得到 0 或 1 作為該建築的標記,多個建築物的標記...

LOJ3099 SNOI2019 積木(搜尋)

lca 學長出的我省省選的神仙題目 省強我菜系列 loj3399 我可能說不清楚,對著 理解吧 感覺這題的主要難點是 不要想他具體是怎麼操作的,只要知道他一定存在一種操作方式能夠實現就行了。首先要注意到乙個很重要的性質 對於當前空格所在的點,除非這個點在目標中就是空格,否則一定可以通過一步操作使這個...

JSOI2019 節日慶典

題意 洛谷做法 先來說個暴力 從前往後列舉 k 1,2,n 我們維護這樣乙個集合 p k 集合內任意兩個元素 i,j i,滿足 text s i s j ge k j 1 即有可能在 ge k 的字首中成為答案的集合 考慮從 p 過渡到 p k 最後,對 p k 中選出最小的即可,比較兩元素 i,j...