雅禮集訓 2017 Day7 事情的相似度

2022-06-24 19:21:09 字數 2597 閱讀 5324

\(\text:\)處理了一下排版問題,以及新增 \(\rm lct\) 做法。

如果沒有原題測試,還不知道這道題還要被咕多久......本來就已經咕了乙個寒假了......

傳送門 to loj

最長公共字尾,很難不讓人想到 \(\tt sam\) 的 \(\text\),因為在 \(\text\) 上有:兩個串的最長公共字尾,即為他們所代表的點在樹上的 \(lca\) 對應的 \(\tt maxlen\).

有了這個東西怎麼做?我們考慮如果我們在樹上有一對終點對\(\lang x, y\rang(x,他們在樹上代表的點的 \(lca\) 是 \(u\),那麼我們就已知 \(lcs(x,y)=\tt len[u]\),同時考察這一對終點對於哪些詢問會產生貢獻:類似二維偏序,對於詢問 \(\lang l, r\rang\),只要滿足 \(l\le x,y\le r\) 便可以考慮一下這一對終點是否是最優解。

那麼我們有一種暴力做法:暴力維護每個的 \(\tt endpos\),然後將 \(\tt endpos\) 集合中的每對終點都記錄一下,這樣最多會有 \(\mathcal o(n^2)\) 級別的點對,但是考慮一下二維偏序的過程,編號相鄰的終點對才是能夠被最多的集合包含的點對,所以對於不相鄰的點對,我們實際上沒有必要去儲存他們。

而維護 \(\tt endpos\) 集合,我們考慮使用啟發式合併,處理詢問用掃瞄線加上樹狀陣列,最後複雜度 \(\mathcal o(n\log^2 n)\).

事實上也可以暴力維護。在 luogu 上有大佬給出這種題型的一般處理方法:

此處,我們也可以採用此類方法,依次掃瞄每個右端點,對於乙個確定的 \(r\),乙個詢問 \([l,r]\) 事實上就是找所有 \(l\ge l\) 的最大的 \(lcs(s[1:l],s[1:r])\),但是有幾個問題:

不難發現詢問就是字尾最大值,我們可以使用 \(\rm bit\) 進行維護,但是難點在於處理每個 \(\rm lcs\).

都涉及 \(\rm lcs\) 了,很顯然需要用到 \(\rm sam\),在 \(\rm sam\) 的樹上,兩個字首的 \(\rm lcs\) 就是他們所在點的 \(\rm lca\) 的 \(\rm len\),並且,我們可以採用 這道題 的做法,將每個左端點到根都染上顏色,處理右端點的時候,看從它對應點到根的路徑上,遇到了哪些左端點,遇到了就在 \(\rm bit\) 上進行更新。在染色的時候,顯然編號越大的左端點比編號小的更優(更容易滿足 \(i\ge l\) 的條件),所以可以直接進行顏色覆蓋。

至於染色和爬樹的過程,就和 \(\rm lct\) 的 \(\rm access\) 函式特別相似,我們考慮採用 \(\rm lct\) 進行維護。

時間複雜度 \(\mathcal o(n\log^2 n)\),和啟發式合併一樣呢(但是**難實現很多)(其實也不是特別難實現)。

#include#include#include#includeusing namespace std;

const int maxn=100000+10;

const int maxm=100000+10;

const int sigma=2;

int trie[maxn<<1][sigma];

int fa[maxn<<1];

int len[maxn<<1];

setendpos[maxn<<1];

int lst=1, ncnt=1;

inline void add(const int pos, const int c)

if(++nxt!=endpos[u].end())

endpos[u].erase(*it);

} for(it=endpos[v].begin(); it!=endpos[v].end(); ++it)

endpos[u].insert(*it); }}

int c[maxn+5];

#define lowbit(i) (i&(-i))

inline void modify(int i, const int x)

inline int query(int i)

signed main()

sort(q+1, q+m+1);

for(int i=1, j=1; i<=m; ++i)

for(int i=1; i<=m; ++i) printf("%d\n", ans[i]);

return 0;

}

const int maxn=2e5;

const int sigma=2;

int n, m;

int a[maxn+5], pos[maxn+5];

vectorq[maxn+5];

int ans[maxn+5];

namespace sam\) 的結論:

兩個串的最長公共字尾,即為他們所代表的點在樹上的 \(lca\) 對應的 \(\tt maxlen\).

而後就是,我們除了從詢問考慮有哪些情況符合條件以外,我們還可以反著進行考慮 —— 一種情況會對哪些詢問產生可能的貢獻,在這道題中,我們使用這種思路發現了二維偏序的關係,進而引導我們對演算法進行優化。

雅禮集訓2017Day7事情的相似度

bitset幫助離線合併實現o n w 然後暴力就可以在n 100000時為所欲為 其實還是有點思想,從大到小列舉height值,這樣每次涉及到的問題的答案一定是height 另外脫機會mle?那就分兩次離唄。沒有什麼是一次離線解決不了的,如果有,那就兩次。從height大到小更新可以簡化轉移,因為...

雅禮集訓 2017 Day7 事情的相似度

點此看題 字尾自動機亂殺。他問的是字首之間的最長字尾,我們對正串建出字尾自動機,然後把字首在自動機上面打上標記。根據字尾自動機的性質,最長字尾就是兩個字首在 tt parent tree 上 tt lca 的 len 對於乙個字首對 l,r 那麼他可以對 l leq l,r leq r 的詢問 l,...

雅禮集訓 2017 價

傳送門 乙個不太顯然的最小割做法。我們這麼連邊 源點向藥物連 infty p i 容量的邊,藥物向它對應的藥材連 infty 容量的邊,藥材向匯點連 infty 容量的邊。用源點的流量減去最小割,再負回來就可以求出答案了。怎麼理解呢?割掉一條邊表示不選其對應的藥物或藥材,我們發現最後的方案一定是完美...