時間限制:5000ms
單點時限:1000ms
記憶體限制:256mb
描述小hi平時的一大興趣愛好就是演奏鋼琴。我們知道乙個**旋律被表示為長度為 n 的數構成的數列。小hi在練習過很多曲子以後發現很多作品自身包含一樣的旋律。
旋律可以表示為一段連續的數列,相似的旋律在原數列不可重疊,比如在1 2 3 2 3 2 1 中 2 3 2 出現了一次,2 3 出現了兩次,小hi想知道一段旋律**現次數至少為兩次的旋律最長是多少?
解題方法提示
輸入第一行乙個整數 n。1≤n≤100000
接下來有 n 個整數,表示每個音的數字。1≤數字≤1000
輸出一行乙個整數,表示答案。
樣例輸入
8樣例輸出1 2 3 2 3 2 3 1
小ho:這一次的問題該如何解決呢?
小hi:嗯,這次的問題被稱為最長不可重疊重複子串問題。
小ho:和上次的問題好像啊,但是這一次是不可以重疊的,直接使用上次的演算法似乎行不通喔。
小hi:是的。問題的關鍵就出在直接用 height 陣列不能保證兩字尾不重疊,我們得換個思路考慮。
小ho:可不可以二分答案,轉化成判定問題呢?
小hi:是個好思路,這的確是可行的。我們先二分乙個k,表示我們假設串中存在長度為k的不可重疊重複子串。
小ho:嗯,就是這個意思。
小hi:存在長度為k的不可重複子串等價於存在兩個字尾有長度為k的公共字首(這裡沒有要求不重疊)。我們檢查 height 陣列中有哪些值 ≥ k。並且如果有連續的height值 ≥ k,就把對應的字尾分在同一組。這樣就保證了該組中所有字尾兩兩之間的最長公共字首都是不小於k的。
我們以樣例為例,看一下k=2和k=3的情況。xi
height
k=2k=318
01 2 3 2 3 2 3 111
2 3 160
2 3 2 3 142
>=2
2 3 2 3 2 3 124
>=2
>=3
3 17
03 2 3 151
3 2 3 2 3 133
>=2
>=3
可以看出,當k=2時,"231"和"23231"的公共字首大於等於k,"23231"和"2323231"的公共字首也大於等k,所以這3個排名連續的字尾會被分到一組。同理"3231"和"323231"也會被分到一組。
對於k=3,"23231"和"2323231"分到一組,"3131"和"323231"分到一組。
小ho:我知道了!
小hi:對,沒錯!下面我們要看看能不能找出不重疊的重複子串。對於每一組,我們檢查這些字尾對應的sa值(也就是字尾起點在原串中的位置i)。如果max - min >= k,那麼就說明我們能找出一組不重疊的重複子串。
例如對於k=3,"23231"和"2323231"的sa值是4和2,"3131"和"323231"這一組的sa值是5和3,差值都不滿足大於等於3,所以找不出不重疊的。
對於k=2,第一組max-min=6-2=4滿足大於等於2,所以能找出不重疊的。
我們給出如下c++**:
bool check(int k)小ho:哈哈,不難嘛,我馬上去實現一發!else
return false;
}
#include #include#include
#include
#include
#include
#include
#include
#include
#include
#define inf 2e9
#define met(a,b) memset(a,b,sizeof a)typedef
long
long
ll;using
namespace
std;
const
int n = 2e5+5
;const
int m = 4e5+5
;int cmp(int *r,int a,int b,int
l) int
wa[n],wb[n],wss[n],wv[n];
int rank[n];//
字尾i在sa中的排名
int height[n];//
sa[i]與sa[i-1]的lcp
int sa[n];//
sa[i]表示排名第i小的字尾的下標
void da(int *r, int *sa, int n, int m)
}void calheight(int *r,int n)
intn,m;
intaa[n];
int maxx=1,minn=1
;bool solve(int
k)
else
}return
false;}
intmain ()
printf(
"%d\n
",ans);
return0;
}
hiho一下 第二週
題目名稱 trie樹 小hi和小ho是一對好朋友,出生在資訊化社會的他們對程式設計產生了莫大的興趣,他們約定好互相幫助,在程式設計的學習道路上一同前進。這一天,他們遇到了一本詞典,於是小hi就向小ho提出了那個經典的問題 小ho,你能不能對於每乙個我給出的字串,都在這個詞典裡面找到以這個字串開頭的所...
hiho一下 第128周 字尾自動機
求給定字串s不同子串的個數 即求該字串構成的字尾自動機裡面包含了多少個字尾 等價於求這個字尾自動機裡面的路徑的個數 每個字尾自動機節點所包含的字尾集合大小為len p len link p 其中len為該節點到根的長度,link為該節點的字尾鏈結 求和輸出即可 include include inc...
hiho一下第二週 Trie樹
小hi和小ho是一對好朋友,出生在資訊化社會的他們對程式設計產生了莫大的興趣,他們約定好互相幫助,在程式設計的學習道路上一同前進。這一天,他們遇到了一本詞典,於是小hi就向小ho提出了那個經典的問題 小ho,你能不能對於每乙個我給出的字串,都在這個詞典裡面找到以這個字串開頭的所有單詞呢?身經百戰的小...