Description
给定一个长度为 \(n\) 的字符串 \(S\),求它的所有前缀中,哪些可以被划分为 \(ABAB...ABA\) 的形式,其中 \(A,B\) 是可以为空的串,且一共包含了 \(k\) 组 \(AB\)。
Solution
考虑令 \(S=AB\),枚举 \(S\) 的长度 \(i\),我们只需要检查 \(LCP(ji+1,1) \ge i, j=1..k-1\),如果都满足,则可以将答案序列中往后的一段覆盖为 \(1\)
用扩展 KMP 可以在 \(O(n)\) 时间内完成对 \(LCP(i,1), i=1..n\) 的计算
所有被枚举的长度共有 \(O(n/k)\) 个,每次需要检查 \(O(k)\) 个位置,故总复杂度 \(O(n)\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
namespace exkmp
{
int nxt[N]; // x[0..m-1] x[i..m-1] LCP
int ext[N]; // x[0..m-1] y[i..n-1] LCP
void presolve(const char* x,int m)
{
nxt[0]=m;
int j=0;
while(j+1<m&&x[j]==x[j+1]) j++;
nxt[1]=j;
int k=1;
for(int i=2; i<m; i++)
{
int p=nxt[k]+k-1, l=nxt[i-k];
if(i+l<p+1) nxt[i]=l;
else
{
j=max(0ll,p-i+1);
while(i+j<m && x[i+j]==x[j]) j++;
nxt[i]=j;
k=i;
}
}
}
void presolve(string s)
{
presolve(s.c_str(),s.length());
}
int lcp(int p)
{
return nxt[p-1];
}
} // namespace exkmp
int n,k;
string s;
namespace sumsolver
{
int a[N];
void modify(int l,int r)
{
r=min(r,n);
l=max(l,1ll);
a[l]++;
a[r+1]--;
}
void solve()
{
for(int i=1;i<=n;i++) a[i]+=a[i-1];
}
int query(int p)
{
return a[p]?1:0;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>k>>s;
exkmp::presolve(s);
for(int i=1;i*k<=n;i++)
{
int flag=1;
for(int j=1;j<k;j++)
{
if(exkmp::lcp(i*j+1)<i)
{
flag=0;
break;
}
}
if(flag)
{
sumsolver::modify(i*k,i*k+min(exkmp::lcp(i*k+1),i));
}
}
sumsolver::solve();
for(int i=1;i<=n;i++) cout<<sumsolver::query(i);
}