题解 图案
真·全场唯一没做出来 T1 的人
发现这个 \(k\) 是定值,十分奇怪
那么枚举 \(|AB|\) 的长度,暴力 hash 向后判 \(k\) 段
这样是 \(O(n\ln n)\) 的
那么再向后二分合法的 \(B\) 的最长长度,覆盖即可
复杂度 \(O(n\ln n+n\log n)\)
其实赛时思路稍微拓展一下也是可以做的
\(n^2\) 暴力是跳 nxt
发现跳 nxt 时得到的结果是单调的
而我们需要结果在一个区间内
于是倍增就好了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define ull unsigned long long
//#define int long long
int n, k;
char s[N];
ull h[N], pw[N];
const ull base=13131;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
namespace force{
int ans[N];
int calc(int n) {
// cout<<"calc: "<<n<<endl;
int lena, lenb;
ull hab, hb;
for (lena=0; lena<=n; ++lena) if ((n-k*lena>=0) && (n-k*lena)%(k+1)==0) {
hab=hb=0;
lenb=(n-k*lena)/(k+1);
// cout<<"lenab: "<<lena<<' '<<lenb<<endl;
for (int i=1; i<=lenb; ++i) hb=hb*base+s[i];
for (int i=1; i<=lena+lenb; ++i) hab=hab*base+s[i];
int pos=1;
for (int i=1; i<=k; ++i) {
if (hashing(pos, pos+lena+lenb-1)!=hab) goto jump;
pos+=lena+lenb;
}
if (lenb && hashing(pos, pos+lenb-1)!=hb) goto jump;
return 1;
jump: ;
}
return 0;
}
void solve() {
pw[0]=1;
for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
for (int i=1; i<=n; ++i) ans[i]=calc(i);
for (int i=1; i<=n; ++i) printf("%d", ans[i]);
printf("\n");
}
}
namespace task1{
int nxt[N], len[N];
bool basic[N], ans[N];
void solve() {
for (int i=2,j=0,t; i<=n; ++i) {
while (j && s[i]!=s[j+1]) j=nxt[j];
if (s[i]==s[j+1]) ++j;
nxt[i]=j;
t=i-j;
if (i%t==0 && (i/t)%k==0) basic[i]=1, len[i]=i/k;
}
// cout<<"basic: "; for (int i=1; i<=n; ++i) cout<<basic[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) {
if (basic[i]) ans[i]=1;
else {
for (int j=nxt[i]; j&&!ans[i]; j=nxt[j]) if (basic[i-j] && j<=len[i-j])
ans[i]=1;
}
}
if (k==1) for (int i=1; i<=n; ++i) printf("1");
else for (int i=1; i<=n; ++i) printf("%d", ans[i]);
printf("\n");
}
}
namespace task2{
bool ans[N];
void solve() {
int t=2*k;
for (int i=1; ; ++i) {
int l=i*t, r=min(i*t+(2*i), n);
for (int j=l; j<=r; ++j) ans[j]=1;
if (r==n) break;
}
for (int i=1; i<=n; ++i) printf("%d", ans[i]);
printf("\n");
}
}
namespace task{
int ans[N];
void solve() {
pw[0]=1;
for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
ll pos=1ll*k*i;
int l, r, mid;
if (pos>n) break;
for (int j=2; j<=k; ++j) if (h[i]!=hashing(i*(j-1)+1, i*j)) goto jump;
l=pos+1, r=min(pos+i, 1ll*n);
while (l<=r) {
int mid=(l+r)>>1;
// cout<<"mid: "<<l<<' '<<r<<' '<<mid<<endl;
if (h[mid-pos]==hashing(pos+1, mid)) l=mid+1;
else r=mid-1;
}
// cout<<"lr: "<<pos-1<<' '<<l-1<<endl;
++ans[pos], --ans[l];
jump: ;
}
for (int i=1; i<=n; ++i) ans[i]+=ans[i-1];
for (int i=1; i<=n; ++i) printf(ans[i]?"1":"0");
printf("\n");
}
}
signed main()
{
freopen("pattern.in", "r", stdin);
freopen("pattern.out", "w", stdout);
scanf("%d%d%s", &n, &k, s+1);
// force::solve();
bool tag=1;
char lst=s[1];
for (int i=2; i<n; ++i) {
if (lst!=s[i+1]) tag=0;
else lst=s[i];
}
// if (tag && n>2500) task2::solve();
// else task1::solve();
task::solve();
return 0;
}