题目链接
题意
给定一个串
T
,对它的每一个前缀能否写成
思路
能否被表示为
k
个循环节和另外一小段(可为空)的和。
另外还有一种特殊情况,就是
能否恰好被表示为
k+1
个循环节的和。
// 其实想到第一步就 Orz 一切都顺了…。
于是求出 fail 数组,然后 i−fail[i] 即为这一段中最小的循环节的长度,记为 cir . 显然, cir 的整数倍也是循环节,即 t∗cir 也是循环节。
要满足题意,则要求
it∗cir==k || ((t∗cir) | i且it∗cir==k+1))
那么就可以直接根据 i,cir,t 的已知条件来 O(1) 算出是否存在这样的 t ,即
算法复杂度 O(n) .
Code
#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
int f[maxn], n, k;
char s[maxn];
typedef long long LL;
void getfail() {
f[0] = f[1] = 0;
for (int i = 1; i < n; ++i) {
int j = f[i];
while (j && s[i] != s[j]) j = f[j];
f[i+1] = s[i] == s[j] ? j+1 : 0;
}
}
bool check(int l, int cir) {
int upp = l / k, down = l / (k+1) + 1;
upp = upp / cir, down = ceil(1.0 * down / cir);
return upp >= down || (l % (k+1) == 0 && (l / (k+1)) % cir == 0);
}
void work() {
scanf("%s", s);
getfail();
for (int i = 1; i <= n; ++i) {
int mincir = i - f[i], cir = mincir;
printf("%d", check(i, cir));
}
printf("\n");
}
int main() {
while (scanf("%d%d", &n, &k) != EOF) work();
return 0;
}