洛谷 P10716
并不难的串串。两只 \(\log\) 是随便做的,这里讨论一只 \(\log\) 怎么做。
由于老师讲的 zlt 做法,个人代码也借鉴了 zlt 的清新写法,还是不交 tj 了。
首先将题意翻译成求多少个 \(S\) 的前缀串可以在前缀 \(i\) 中不重叠地出现 \(k\) 次,且最后一次出现顶到了 \(i\)。
自然地,对于每个前缀串 \(S[1,i]\),求出第一个满足其能不重叠出现 \(j\) 次的位置 \(f_{i,j}\)。这可以做到 \(O(n\alpha(n)\ log\ n)\):
先跑一遍 exkmp 求出所有 \(LCP(S,S[j,n])\) 记为 \(z_j\),然后枚举前缀串 \(S[1,i]\) 并贪心向右匹配,问题变成了 \(n\ log\ n\) 次查询,每次查询要求出位置 \(p\) 及其右边第一个满足 \(z_j\ge i\) 的位置 \(j\)。于是想到对 \(i\) 扫描线,并开一个并查集维护合法的 \(j\),支持删除和后继查询,于是就做到了上述的复杂度。
求出了所有 \(f_{i,j}\) 之后就可以开始考虑每次询问。由于最后一次出现必须恰好顶到 \(i\),考虑跑一遍 kmp 建出失配树,那么相当于满足条件的串一定在 \(i\) 的祖先中。
然后我们又可以注意到一个关键性质:显然越往上跳就越能满足条件,也就是说满足条件的串一定是 \(i\) 到根的链的上半段。所以考虑直接倍增找出这一段,利用 \(f_{i,j}\) 即可 \(O(1)\) 判断合法性,于是这一部分总复杂度 \(O(q\ log\ n)\)。
总复杂度为 \(O(n\alpha(n)\ log\ n+q\ log\ n)\)。
code
#include <bits/stdc++.h>
//taskkill /f /im 未命名1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define print(a,l,r) for(int i=l;i<=r;++i) cerr<<a[i]<<' ';puts("");
#define popcnt __builtin_popcount
#define all(s) s.begin(),s.end()
#define bstring basic_string
//#define add(x,y) (x+=y)%=mod
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define ll long long
//#define ull unsigned long long
using namespace std;
const int N=2e5+5,INF=2e9,mod=1e9+7;
int t,n,m;
char s[N];
int z[N];vector<int> S[N];
int p[18][N],dep[N],fa[N];
vector<int> val[N];
int find(int u) {
if(u==fa[u]) return u;
else return fa[u]=find(fa[u]);
}
void kmp() {
for(int i=2,j=0;i<=n;++i) {
while(j&&s[i]!=s[j+1]) j=p[0][j];
if(s[i]==s[j+1]) ++j;
p[0][i]=j;
}
}
void exkmp() {
int l=1,r=0;z[1]=n;
for(int i=2;i<=n;++i) {
if(i>r) z[i]=0;
else z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=n&&s[z[i]+1]==s[i+z[i]]) ++z[i];
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
}
void sol() {
scanf("%d",&n);
scanf("%s",s+1);
kmp(),exkmp();fa[n+1]=n+1;
for(int i=1;i<=n;++i) {
S[z[i]].epb(i),fa[i]=(z[i]?i:i+1);
}
for(int i=1;i<=n;++i) {
int p=1;
while(p+i-1<=n) {
val[i].epb(p+i-1);
p=find(p+i);
}
for(auto it:S[i]) {
fa[it]=it+1;
}
}
for(int i=1;i<=n;++i) {
dep[i]=dep[p[0][i]]+1;
}
for(int i=1;i<18;++i) {
for(int j=1;j<=n;++j) {
p[i][j]=p[i-1][p[i-1][j]];
}
}
int q,id,k;scanf("%d",&q);
while(q--) {
scanf("%d%d",&id,&k);
if(k==1) {
puts("1");continue;
}
int ps=id;
for(int j=17;j>=0;--j) {
int to=p[j][ps];
if(to&&(val[to].size()<k||val[to][k-1]>id)) {
ps=to;
}
}
printf("%d\n",dep[ps]-1);
}
}
int main()
{
t=1;
while(t--) {
sol();
}
return 0;
}

浙公网安备 33010602011771号