這道題是字尾陣列的乙個典型應用。求乙個串中連續重複次數最多的乙個子串。做這道題的時候要把握住,連續重複 和 次數最多這兩個關鍵,才能有突破。
下面的思路是照搬大牛的:(大神不要打我
在字尾陣列神文中有這題的題解。
比較容易理解的部分就是列舉長度為l,然後看長度為l的字串最多連續出現幾次。
既然長度為l的串重複出現,那麼str[0],str[l],str[2*l]……中肯定有兩個連續的出現在字串中。
那麼就列舉連續的兩個,然後從這兩個字元前後匹配,看最多能匹配多遠。
即以str[i*l],str[i*l+l]前後匹配,這裡是通過查詢suffix(i*l),suffix(i*l+l)的最長公共字首
通過rank值能找到i*l,與i*l+l的排名,我們要查詢的是這段區間的height的最小值,通過rmq預處理
達到查詢為0(1)的複雜度
,設lcp長度為m, 則答案顯然為m / l + 1, 但這不一定是最好的, 因為答案的首尾不一定再我們列舉的位置上. 我的解決方法是, 我們考慮m % l的值的意義, 我們可以認為是後面多了m % l個字元, 但是我們更可以想成前面少了(l - m % l)個字元! 所以我們求字尾j * l - (l - m % l)與字尾(j + 1) * l - (l - m % l)的最長公共字首。
即把之前的區間字首l-m%l即可。
然後把可能取到最大值的長度l儲存,由於 題目要求字典序最小,通過sa陣列進行列舉,取到的第一組,肯定是字典序最小的。
我的**如下:
#include#include#include#include#include#include#define maxd 100010
#define maxl 300
using namespace std;
int r[maxd], rank[maxd], height[maxd];
int sa[maxd], wa[maxd], wb[maxd], ws[maxl], wv[maxd]; //ws 的大小是最大字元的大小。其他的是串長大小
//r陣列存放字元的值
int cmp(int *p, int x, int y, int l)
void da(int n, int m) //n為字串長度,m為字元的最大值
}void calheight(int n) //n為串的長度減一
/*****************以上都是字尾陣列模板,下面的是具體問題的處理。******************/
char str[maxd];
int dp[maxd][20];
int cnt=0,maxtime=0;
void rmq(int n)
else if(time==maxtime)}}
if(cnt==0||maxtime==1)
int start=0,len=-1;
for(i=1;i=a[j]*(maxtime-1))}}
for(i=start;i
poj3693 字尾陣列 RMQ
感覺思路還是非常神奇的。另外注意一下strlen好像是個on的函式。日狗。tle了乙個晚上。include include include includeusing namespace std define maxn 100005 define forup i,a,b for int i a i b...
POJ 3693 字尾陣列 RMQ
點選開啟鏈結 題意 問連續重複部分最多的串是什麼,不能重疊,且我們要字典序最小的串如xbcabcab,有bcabca重複次數為2,cabcab重複次數也為2,那麼要前邊那個 思路 以前寫過乙個類似的,spoj 687,這個只是求連續重複部分最多的串的次數,並不需要將按字典序最小串輸出,那麼我們可以用...
字尾陣列 poj 3693
題目 給出乙個串,求重複次數最多的連續重複子串 列舉長度為l,然後看長度為l的字串最多連續出現幾次。既然長度為l的串重複出現,那麼str 0 str l str 2 l 中肯定有兩個連續的出現在字串中。那麼就列舉連續的兩個,然後從這兩個字元前後匹配,看最多能匹配多遠。即以str i l str i ...