1. 程式人生 > >Codeforces 526D Om Nom and Necklace 迴圈節 kmp

Codeforces 526D Om Nom and Necklace 迴圈節 kmp

題目連結

題意

給定一個串 T,對它的每一個字首能否寫成 A+B+A+B+...+B+A 的形式(kAk+1B,均可為空串)

思路

A+B+A+B+...+B+A 可以看做 AB+AB+AB+...+A,即 kAB1A. 也就是判斷這個串
能否被表示為 k 個迴圈節和另外一小段(可為空)的和
另外還有一種特殊情況,就是 A 為空,此時即該串
能否恰好被表示為 k+1 個迴圈節的和

// 其實想到第一步就Orz一切都順了…。

於是求出 fail 陣列,然後 ifail[i] 即為這一段中最小的迴圈節的長度,記為 cir. 顯然,cir 的整數倍也是迴圈節,即 t

cir 也是迴圈節。

要滿足題意,則要求

itcir==k||((tcir)|iitcir==k+1))
那麼就可以直接根據 i,cir,t 的已知條件來 O(1) 算出是否存在這樣的 t,即 O(1) check

演算法複雜度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; }