BZOJ4310 跳蚤 字尾陣列 ST表 二分

2021-08-17 02:13:46 字數 2073 閱讀 2597

趕緊寫完,,,,,就能快點回去洗澡了~

bzoj4310傳送門

給乙個長度不超過100000的字串。現在要把這個字串分成k組(k不超過length),然後對於每一組,取其字典序最大的子串,得到乙個集合s,記s中字典序最大的那個串為ss,詢問ss字典序最小可以是什麼

輸入格式:

第一行乙個整數k,含義如題

接下來一行乙個字串

輸出格式:

輸出所求字串

看了hxy的題解 這個做法比較神 或者me太蠢

頭一次知道字尾陣列還可以這麼玩

因為要最大的最小,不妨考慮二分求出答案 臥槽字串怎麼二分?

首先,乙個字串的不同子串個數=∑

len−

sa[i

]−he

ight

[i]+

1 =∑l

en−s

a[i]

−hei

ght[

i]+1

(me的字串下標從1開始)。根據定義還是比較顯然的,請一定要想明白!

於是二分的上下界就有了。假設二分到了乙個mid,求出第mid小的子串

s s

,check的時候從後往前貪心的分組,如果分的組數大於k就不行。貪心分組是顯然的,如果[i

,j]' role="presentation">[i,

j][i

,j]的字典序大於了

s s

,那麼肯定在

i' role="presentation">ii和

i+1 i+1

之間切一刀(第乙個字母就比

s s

大的情況特殊討論)。快速比較字典序可以用st表查lcp

那麼如何求出第mid小的子串呢?從1到n列舉字尾的排名,如果mid大於了當前字尾貢獻的數量,那麼mid -= dif[i],不然的話,說明所求字串就是l=

sa[i

]' role="presentation">l=s

a[i]

l=sa

[i],

r=sa

[i]+

heig

ht[i

]+mi

d−1 r=s

a[i]

+hei

ght[

i]+m

id−1

,這裡也請一定要想明白!

然後這題就做完了

#include #include #include using namespace std ;

char ss[100005] ;

int k , len , logg[100005] , mi2[30] , st[17][100005];

int sa[100005] , rk[100005] , tp[100005] , buc[100005] , he[100005] , dif[100005] ;

bool cmp( int *f , int x , int y , int d )

void rsort( int *rk , int *tp , int x )

void getsa() if( ::rk != rk ) memcpy( ::rk , rk , sizeof( ::rk ) ) ;

for( int i = 1 , j , k = 0 ; i <= len ; he[ rk[i++] ] = k )

for( j = sa[ rk[i]-1 ] , k = k ? k - 1 : k ; ss[i+k] == ss[j+k] ; k ++ ) ;

}void prework()

int query( int l , int r )

int global_l , global_r ;

void getstring( long long left , int i = 1 )

bool check()

} return true ;

}void solve()

for( int i = ansl ; i <= ansr ; i ++ )

printf( "%c" , ss[i] ) ;

}int main()

BZOJ4310 跳蚤 字尾陣列 二分

很久很久以前,森林裡住著一群跳蚤。一天,跳蚤國王得到了乙個神秘的字串,它想進行研究。首先,他會把串 分成不超過 k 個子串,然後對於每個子串 s,他會從s的所有子串中選擇字典序最大的那乙個,並在選出來的k個子串中選擇字典序最大的那乙個。他稱其為 魔力串 現在他想找乙個最優的分法讓 魔力串 字典序最小...

BZOJ4310 跳蚤(字尾陣列 二分答案)

傳送門 dar kbzo jdarkbzoj darkbz oj上題面有誤,應該是最大的最小 考慮二分這個最小的串x xx的排名k kk那麼也就是說所有排名比這個大的一定要被切開 考慮乙個字尾s p n s p,n s p,n 如果l cp s p n x 0 lcp s p,n x 0 lcp s...

BZOJ4310 跳蚤(字尾陣列 二分答案)

注意到答案一定是原串的子串,於是考慮造出sa,二分答案是第幾小的子串。第k小子串很容易在sa上求出。之後計算使他成為最大子串至少要在幾個位置切割,對每個字典序比答案大的字尾,找到所有合法切割位置 求lcp即可 就轉化成了選最少的點使每個區間都包含至少乙個點的經典問題。include include ...