給定字串$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_kusing 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。...