POI2000 迷宮的牆

2022-04-29 20:15:09 字數 1704 閱讀 2695

迷宮的牆

給出一棵有 \(n-1\) 個節點樹,每個節點都有一種顏色,一共只有三種顏色,每個非葉子節點的出度為 \(3\)。

每個節點都指向編號比自己大的節點

樹以 \(1\) 號節點為根,樹的所有葉子節點都指向節點 \(n\),而且每個節點的三條邊是有順序的,編號為 \(1,2,3\)。

針對每一條 \(1\to n\) 的路徑,我們可以用一次遍歷的顏色邊的編號來代表它,從而得到原樹的顏色路徑集合

如果樹中存在某些節點,刪除它們之後 將剩餘節點重新連邊 發現仍然可以構造出與原來相同的顏色路徑集合。

那麼它們被認為是可以刪除的,求刪除之後的樹的總結點數。

倒序處理+hash

這道題看上去很不可做,給定條件很多而且複雜,主要問題是思維的轉化。

給出方法:乙個節點是可刪除的,當且僅當樹中存在它的等價節點

其中兩個節點是等價的,僅當兩者顏色相同,兩者子節點也是等價的(或相同的),而且子節點排列順序相同。

證明:

兩個節點指向相同或等價節點,表示我完全可以將編號較小的節點刪去,

將指向它的邊重新指向編號較大的節點,從而完成一次完美的刪除。

由於子節點排列順序相同,且兩者顏色相同,所以保證了路徑上遍歷的顏色邊的編號均相同。

值得注意的是,根據定義,如果兩個節點是等價的,那麼以兩者為根的子樹形成了一一對應的等價關係。

相當於我們找到了兩個同構的子樹,顯然可以任意刪去乙個。

根據上面的定義,需要判斷兩個節點是否為等價節點,必須事先判斷其子節點。

所以我們採用編號從大到小倒序處理。

對於每個節點,我們將它的子節點與它的顏色組合在一起,進行一次 hash,存入 map 中。

當出現相同的 hash 值時,就將當前節點(編號較小)替換為 map 中原有的節點(編號較大)。

具體流程是醬紫的:

設 \(to(i)\) 表示 \(i\) 節點的等效節點,首先令 \(to(i)=i,ans=n\)。

倒序處理節點,對於每乙個節點 \(i\),設其子節點為 \(a,b,c\),其顏色為 \(c(i)\)。

令 \(hash=c(i)\times n^3+to(a)\times n^2+to(b)\times n+to(c)\)。(可以證明不存在 hash 衝突)

如果 \(mp(hash)=j\),則令 \(to(i)=j,ans--\)。

否則令 \(mp(hash)=i\)。

重複執行 \(2\to 5\),直至結束,當前的 \(ans\) 即為答案。

#include#include#include#include#define n 6010

using namespace std;

int n;

int c[n],to[n];

int a[n][5];

mapmp;

int read()

int main()

}printf("%d\n",ans);

return 0;

}

POI2000 最長公共子串

求多個串的最長公共子串。聽說如果會 sa m 的話這題就很簡單了 然而我只會用 sa 做,具體做法是先用不同的分隔符把字串接成乙個串 然後還是按 he ight i 從大到小將 i 的集合與 i 1的集合合併 對每個集合維護乙個 se t i 用來記錄 i 的集合中出現了哪些字串的子串 注意 se ...

AC自動機 POI2000病毒

題意 給你一些字串,問能不能找到乙個無限長的字串,使得給定的這些字串不會出現在該無限長字串中 一般我們寫ac自動機都是盡可能的使多匹配,而本題反其道而行,要盡可能的不匹配,那麼我們可以遇到fail標記就跳 因為乙個字串的標記是在最後,中途就調走了肯定就不會遇到了 如果存在乙個無限長的字串,那麼我們內...

POI2000 最長公共子串

給出幾個由小寫字母構成的單詞,求它們最長的公共子串的長度。任務輸入 檔案的第一行是整數 n,1 n 5,表示單詞的數量。接下來n行每行乙個單詞,只由小寫字母組成,單詞的長度至少為1,最大為2000。輸出 僅一行,乙個整數,最長公共子串的長度。樣例輸入 3 abcb bcaacbc樣例輸出 2 題解 ...