contest
I
先从I说起:
题意:求lcp(i,j) == k,要求lcp字典序最小,在此条件下有序对(i,j)最小。
这道题本来是应该30min内AC的,
首先,看到题太激动,没有看样例,连字典序最小的要求都没有看到就开始写了。这样没有理清细节就开始写一定不可能一次AC!
之后找到了正解,忘了判0,然后还是WA。完全找不到错,开始对拍。
然而对拍的时候粘了以前的输出(其实是完全没有意识到错误),特判0的时候:
if ( !ans[p].len ){ //不能直接用lcp的长度特判是否有答案,长度是0不就错了吗。
if ( !p ) puts("-1 -1");
else printf("%d %d\n",n - p + 1,n - p + 1);
}
else{
node2 tmp = (node2){n - p + 1,n - p + 1,rk[n - p],p};
if ( tmp < ans[p] ) printf("%d %d\n",n - p + 1,n - p + 1);
else printf("%d %d\n",ans[p].id1,ans[p].id2);
}
更不应该的是,手造了明显会WA的数据,然而想当然的以为0的时候就是-1,-1
其实只有所有字母相同时才是-1,-1!!!
必须仔细的反思自己思维的每个细节,才能找到错!
这道题考场上调了1h多,下来调了25min,就因为这样一个小错误。只有真正仔细才能避免!
说下这题正解:
求出后缀数组,按照h[i]倒序合并,每次可以选出的两块的后缀位置最小的更新答案。至于lcp字典序,因为求出后缀数组了,就很好比较了。(注意不能只看在后缀数组中的位置,因为lcp可能相同)
当然可以用后缀树,在lca处更新答案,但是lcp的字典序比较稍微有点麻烦
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define repd(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<S.size();++i)
#define fore(i,x) for(int i = head[x] ; i ; i = e[i].next)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
const int maxn = 200020;
char s[maxn];
int n,c[maxn],t1[maxn * 2],t2[maxn * 2],sa[maxn],rk[maxn],h[maxn];
int mn[20][maxn * 2],cnt[maxn * 2];
struct node{
int l,id;
bool operator < (node a)const{
if ( l == a.l ) return id < a.id;
return l < a.l;
}
}dt[maxn];
int tot;
void suffix_array(){
int m = 200 , *x = t1 , *y = t2;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[i] = s[i]]++;
rep(i,1,m) c[i] += c[i - 1];
rep(i,0,n - 1) sa[--c[x[i]]] = i;
for (register int k = 1 ; k < n ; k <<= 1){
int p = 0;
memset(y,0,sizeof(t1));
repd(i,n - 1,n - k) y[p++] = i;
rep(i,0,n - 1) if ( sa[i] >= k ) y[p++] = sa[i] - k;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[y[i]]]++;
rep(i,1,m) c[i] += c[i - 1];
repd(i,n - 1,0) sa[--c[x[y[i]]]] = y[i];
p = 0 , swap(x,y) , x[sa[0]] = ++p;
rep(i,1,n - 1) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]]) && (y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
if ( p >= n ) break;
m = p;
}
rep(i,0,n - 1) rk[sa[i]] = i;
int k = 0;
rep(i,0,n - 1){
if ( !rk[i] ) continue;
int j = sa[rk[i] - 1];
if ( k ) k --;
while ( s[j + k] == s[i + k] ) k++;
h[rk[i]] = k;
dt[++tot] = (node){k,rk[i]};
}
sort(dt +1,dt + tot + 1);
//rep(i,1,tot) cout<<dt[i].l<<" "<<dt[i].id<<endl;
//cout<<endl<<endl;
}
inline int lcp(int x,int y){
if ( x == y ) return n;
if ( x > y ) swap(x,y);
x++;
int c = cnt[y - x + 1];
return min(mn[c][x],mn[c][y - (1 << c) + 1]);
}
struct node2{
int id1,id2,pos,len,tag;
//node2(){};
bool operator < (node2 a)const{
int l2 = lcp(pos,a.pos);
if ( l2 >= len ){ // the lcp is equal
if ( id1 == a.id1 ) return id2 < a.id2;
return id1 < a.id1;
}
return s[sa[pos] + l2] < s[sa[a.pos] + l2];
}
}ans[maxn];
int mn2[maxn],fa[maxn];
void init(){
int k = 0;
rep(i,0,n){
if ( i > (1 << (k + 1)) ) k++;
cnt[i] = k;
}
rep(i,0,n - 1) mn[0][i] = h[i];
rep(i,1,19)
rep(j,0,n - 1)
if ( j + (1 << (i - 1)) < n ) mn[i][j] = min(mn[i - 1][j],mn[i - 1][j + (1 << (i - 1))]);
else mn[i][j] = mn[i - 1][j];
}
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]);}
void init_ans(){
rep(i,0,n) fa[i] = i , mn2[i] = sa[i] + 1;
repd(i,tot,1){
int id = dt[i].id , len = dt[i].l;
int p = getfa(id - 1) , q = getfa(id);
node2 cur = (node2){mn2[p],mn2[q],id,len,1};
if ( cur.id1 > cur.id2 ) swap(cur.id1,cur.id2);
if ( !ans[len].tag || cur < ans[len] ) ans[len] = cur;
fa[p] = q , mn2[q] = min(mn2[q],mn2[p]);
}
}
int main(){
// freopen("input.txt","r",stdin);
scanf("%s",s);
n = strlen(s);
suffix_array();
init();
init_ans();
int m;
scanf("%d",&m);
while ( m-- ){
int p;
scanf("%d",&p);
if ( !ans[p].tag ){
if ( !p ) puts("-1 -1");
else printf("%d %d\n",n - p + 1,n - p + 1);
}
else{
node2 tmp = (node2){n - p + 1,n - p + 1,rk[n - p],p};
if ( tmp < ans[p] ) printf("%d %d\n",n - p + 1,n - p + 1);
else printf("%d %d\n",ans[p].id1,ans[p].id2);
}
}
}