想定解じゃないのが通りまくっている様子だが、チャレンジケース追加で通らなくなった。
http://yukicoder.me/problems/no/515
問題
N個の文字列S[i]が与えられる。
M個のクエリ(i,j)が与えられるので、それぞれS[i],S[j]の最長共通接頭辞の長さの総和を求めよ。
解法
チャレンジケース追加前はローリングハッシュで通ったが、追加後はそれでは通らなくなった。
事前にS[x]をソートしておいて隣接要素同士のLCPを求めておこう。
各クエリはS[i]およびS[j]がソート後a,b番目だったとする。以下a<bとする。
その場合、a,a+1,a+2,....,b番目の文字列のLCPを求めることと等しい。
これは(aとa+1)、(a+1とa+2)...(b-1,b)のLCP長の最小値となる。
よってRMQの問題に帰結できる。
あとは各クエリをSegTreeまたはSparse Treeで処理していく。
クエリが重いので後者の方がよさそう。
ll N; string S[101010]; pair<string,int> P[101010]; int ID[101010]; ll M,X,D; int com[101010][20]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N; FOR(i,N) { cin>>S[i]; P[i]={S[i],i}; } sort(P,P+N); FOR(i,N) ID[P[i].second]=i; FOR(i,N-1) { x=P[i].second; y=P[i+1].second; FOR(r,min(S[x].size(),S[y].size())) if(S[x][r]!=S[y][r]) break; com[i][0]=r; } for(x=1;x<=19;x++) FOR(i,N-1) if(i+(1<<(x-1))<N) com[i][x]=min(com[i][x-1],com[i+(1<<(x-1))][x-1]); ll ret=0; cin>>M>>X>>D; for(int k=1;k<=M;k++) { x=X/(N-1); y=X%(N-1); if(x>y) swap(x,y); else y++; X = (X+D) % (N*(N-1)); x=ID[x]; y=ID[y]; if(x>y) swap(x,y); r=0; while(1<<(1+r)<=y-x) r++; ret += min(com[x][r],com[y-(1<<r)][r]); } cout<<ret<<endl; }
まとめ
Sparse Tableはまだこれで2回しか使ったことがない。
なので解法が頭に浮かばない…。