BZOJ3230 相似子串 字串 SA ST表

2022-03-31 15:52:31 字數 1638 閱讀 8673

給定字串$s$。長度為$n$。

現在有$q$組詢問,每組詢問內容如下:

兩個正整數$i,j$。

設$s_i,s_j$分別表示$s$的所有本質不同的子串中字典序第$i$小和第$j$小的子串。

請你輸出$|lcp(s_i,s_j)|^2+|lcs(s_i,s_j)|^2$。

如果不存在$s_i$或者$s_j$,則輸出$-1$。

$n,q\leq 10^5$

這題大概是我做的前幾題$sa$的大整合+公升級版吧。

我們考慮如何找到本質不同子串中第$k$大的子串。

我們考慮按照串$s$的字尾大小從小到大處理。

對於排名為$i$的字尾$sa[i]$,考慮它 除了與排名更靠前的其他字尾

的相同字首以外的字首所代表的子串。

很顯然,這些子串都是本質不同的。根據字尾陣列的性質,也很顯然,這些串都不同於之前已經計算過的串。不然的話,$height[i]$會更大。

而且,這些子串是按照字典序排的。

現在,我們發現這些後,不需要處理出所有子串。

統計原串字尾排名前$i$的字尾所包含的子串的個數,記為$presum[i]$。

顯然,$presum[i]=presum[i-1]+len(sa[i])-height[i]$。

於是我們在查詢第$k$大子串的時候就可以通過二分或者倍增來快速地找到第$k$大的子串所在的字尾,然後確定第$k$大的子串就容易了。

至於求兩個子串的$lcp$和$lcs$長度,是字尾陣列的經典操作,這裡就不加贅述了。

#include #define rank r_a_n_k

using namespace std;

typedef long long ll;

const int n=200005;

int n,q;

int sa[n],rank[n],height[n],tax[n],tmp[n];

int ssa[n],srank[n],sheight[n];

int st[n][19];

ll presum[n];

char s[n];

void sort(int n,int m,int sa,int rank)

bool cmp(int rk,int x,int y,int w)

void suffix_array(char s,int n,int sa,int rank,int height)

for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)

for (k=max(k-1,0),j=sa[rank[i]-1];s[i+k]==s[j+k];k++);

height[1]=0;

}void get_st(int n) }}

int query(int l,int r)

getsubstr(k1,l1,r1);

getsubstr(k2,l2,r2);

ll len=min(r1-l1+1,r2-l2+1);

ll lcp=min(len,(ll)lcp(l1,l2)),lcs=min(len,(ll)lcs(r1,r2));

printf("%lld\n",lcp*lcp+lcs*lcs);

} return 0;

}

bzoj 3230 相似子串

time limit 20 sec memory limit 128 mb submit 1767 solved 438 submit status discuss 輸入第1行,包含3個整數n,q。q代表詢問組數。第2行是字串s。接下來q行,每行兩個整數i和j。1 i j 輸出共q行,每行乙個數表示...

BZOJ 3230 相似子串

給定乙個長度為 n 的字串以及 q 組查詢,每組查詢給定 a 和 b 求在所有本質不同子串中排名第 a 和第 b 的串的最長公共字首與最長公共字尾的平方和.n,q le 1 times 10 5 字尾陣列板子題.麻麻我終於會用字尾陣列辣 本來想接著用sam的.但是發現多組查詢排名為 k 的本質不同子...

BZOJ3230 相似子串

3230 相似子串 time limit 20 sec memory limit 128 mb submit 913 solved 223 submit status description input 輸入第1行,包含3個整數n,q。q代表詢問組數。第2行是字串s。接下來q行,每行兩個整數i和j。...