題目
正解
辣雞數據結構題。
考慮某個串出現的所有位置的右端點。設相鄰位置之差爲(),於是它覆蓋的位置爲,也就是
於是考慮維護值在某個區間內的的和、個數。(樹狀數組)
建,建出樹,對於每個節點,如果我們得到了它的集合,二分,試着找到覆蓋位置恰好爲的字符串。
接下來就是維護集合和樹狀數組。
直接上,用維護集合。
至於最終怎麼比較字符串的大小,可以直接字符串哈希二分;或者一開始建反串,這樣跑之後建出的樹就是後綴樹(記得欽定邊的順序,通過位置來比較大小,其中是集合中隨便一個點)。
時間複雜度
代碼
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#define N 40010
#define ll long long
int n,k;
char str[N];
struct Node{
Node *c[26],*fail;
int len;
} d[N];
int cnt;
Node *S,*T;
Node *newnode(){
Node *nw=&d[++cnt];
memset(nw,0,sizeof(Node));
return nw;
}
void insert(char ch){
ch-='a';
Node *nw=newnode();
nw->len=T->len+1;
Node *p=T;
for (;p && !p->c[ch];p=p->fail)
p->c[ch]=nw;
if (!p)
nw->fail=S;
else{
Node *q=p->c[ch];
if (q->len==p->len+1)
nw->fail=q;
else{
Node *clone=newnode();
memcpy(clone,q,sizeof(Node));
clone->len=p->len+1;
for (;p && p->c[ch]==q;p=p->fail)
p->c[ch]=clone;
nw->fail=q->fail=clone;
}
}
T=nw;
}
struct EDGE{
int to;
EDGE *las;
} e[N];
int ne;
EDGE *last[N];
int fa[N];
int pos[N];
ll t0[N],t1[N];
void add(int x,int c,ll t[]){
for (;x<=n;x+=x&-x)
t[x]+=c;
}
ll query(int x,ll t[]){
ll r=0;
for (;x;x-=x&-x)
r+=t[x];
return r;
}
int siz[N],hs[N];
int minr[N];
void init(int x){
siz[x]=1,hs[x]=0;
minr[x]=(pos[x]!=-1?pos[x]:n+1);
for (EDGE *ei=last[x];ei;ei=ei->las){
init(ei->to);
siz[x]+=siz[ei->to];
if (siz[ei->to]>siz[hs[x]])
hs[x]=ei->to;
minr[x]=min(minr[x],minr[ei->to]);
}
}
set<int> s;
int f[N];
void addi(int i,int c){add(i,i*c,t1);add(i,c,t0);}
void geti(int i){
if (s.empty()){
addi(n,1);
s.insert(i);
return;
}
auto p=s.upper_bound(i);
if (p==s.end()){
--p;
addi(i-*p,1);
}
else{
if (p==s.begin()){
addi(*p-i,1);
}
else{
auto q=p;
--q;
addi(*p-*q,-1);
addi(*p-i,1),addi(i-*q,1);
}
}
s.insert(i);
}
void erasei(int i){
s.erase(i);
if (s.empty()){
addi(n,-1);
return;
}
auto p=s.upper_bound(i);
if (p==s.end()){
--p;
addi(i-*p,-1);
}
else{
if (p==s.begin()){
addi(*p-i,-1);
}
else{
auto q=p;
--q;
addi(*p-i,-1),addi(i-*q,-1);
addi(*p-*q,1);
}
}
}
int calc(int len){return query(len,t1)+(query(n,t0)-query(len,t0))*len;}
void insert(int x){
if (pos[x]!=-1)
geti(pos[x]);
for (EDGE *ei=last[x];ei;ei=ei->las)
insert(ei->to);
}
void clear(int x){
if (pos[x]!=-1)
erasei(pos[x]);
for (EDGE *ei=last[x];ei;ei=ei->las)
clear(ei->to);
}
void dfs(int x){
if (hs[x]){
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=hs[x]){
dfs(ei->to);
clear(ei->to);
}
dfs(hs[x]);
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=hs[x])
insert(ei->to);
}
if (x==1)
return;
if (pos[x]!=-1)
geti(pos[x]);
int l=d[x].fail->len+1,r=d[x].len,res=-1;
while (l<=r){
int mid=l+r>>1,tmp=calc(mid);
if (tmp==k){
res=mid;
break;
}
if (tmp>k)
r=mid-1;
else
l=mid+1;
}
f[x]=res;
}
const int mo1=1300000003;
const int mo2=1000000009;
const int mo3=1000000007;
ll pro1[N],pro2[N],pro3[N];
ll pw1[N],pw2[N],pw3[N];
bool comp(int x,int n,int y,int m){
if (n!=m)
return n<m;
int l=1,r=n,t=0;
while (l<=r){
int mid=l+r>>1;
if (((pro1[x+mid]-pro1[x]*pw1[mid])%mo1+mo1)%mo1==
((pro1[y+mid]-pro1[y]*pw1[mid])%mo1+mo1)%mo1 &&
((pro2[x+mid]-pro2[x]*pw2[mid])%mo2+mo2)%mo2==
((pro2[y+mid]-pro2[y]*pw2[mid])%mo2+mo2)%mo2 &&
((pro3[x+mid]-pro3[x]*pw3[mid])%mo3+mo3)%mo3==
((pro3[y+mid]-pro3[y]*pw3[mid])%mo3+mo3)%mo3)
l=(t=mid)+1;
else
r=mid-1;
}
return str[x+t]<str[y+t];
}
int main(){
freopen("that.in","r",stdin);
freopen("that.out","w",stdout);
int Q;
scanf("%d",&Q);
while (Q--){
scanf("%s%d",str,&k);
n=strlen(str);
pw1[0]=pw2[0]=pw3[0]=1;
for (int i=1;i<=n;++i){
pw1[i]=pw1[i-1]*37%mo1;
pw2[i]=pw2[i-1]*43%mo2;
pw3[i]=pw3[i-1]*53%mo3;
}
pro1[0]=pro2[0]=pro3[0]=0;
for (int i=1;i<=n;++i){
pro1[i]=(pro1[i-1]*37+str[i-1]-'a')%mo1;
pro2[i]=(pro2[i-1]*43+str[i-1]-'a')%mo2;
pro3[i]=(pro3[i-1]*53+str[i-1]-'a')%mo3;
}
cnt=0;
memset(pos,255,sizeof pos);
T=S=newnode();
for (int i=0;i<n;++i){
insert(str[i]);
pos[T-d]=i;
}
ne=0;
memset(last,0,sizeof last);
for (int i=2;i<=cnt;++i){
fa[i]=d[i].fail-d;
e[ne]={i,last[fa[i]]};
last[fa[i]]=e+ne++;
}
init(1);
memset(t0,0,sizeof t0);
memset(t1,0,sizeof t1);
s.clear();
dfs(1);
int x=0,len=n+1;
for (int i=2;i<=cnt;++i)
if (f[i]!=-1){
int _x=minr[i]-f[i]+1,_len=f[i];
if (comp(_x,_len,x,len)){
x=_x,len=_len;
}
}
if (x==0 && len==n+1)
printf("NOTFOUND!\n");
else{
str[x+len]=0;
printf("%s\n",str+x);
}
}
return 0;
}