codeforces526D. Om Nom and Necklace【KMP】
飞刀可能进不了前百,但加上小李就能进前三
忙完入学的各种事终于赶去图书馆时,在校内一天只吃了一个面包和巧克力,已是二十点四十。武大规定二十二点半闭馆,我满心期待在两个小时里总能收获些什么,万万没想到会被CF的\(bug\)所连累。这是对我很重要的一天,却是天地间寻常的一天。看着宣传中中国最美大学的景致,我没有一点触动。在四十度天气登上珞珈山,好不容易寻得一块稍稍安静的地方,却又被林立的别墅群搅扰。我想,珞珈山已经见证了无数理想主义者的破碎,自然不屑于一位无名之卒的漠视。
星月北望,风物渐长
春酝花语,秋酿微黄
暮雨朝晴,阡陌绽放
沃野万顷,梅韵凝香
青砖黛瓦,朱街碧巷
繁华宽泛,流年从简
——————梅花可甘心做樱花的滋养?
我打开具体的窗户,吸了一口抽象的空气,研究无知之幕下的电车难题,发现由\(KMP\)得到的最小循环节为\(cir_{min} = x - nxt[x]\),而每一种可能中\(A\)和\(B\)都是确定的,那么每一连续出现的\(A+B\)也是确定的,所以令\(S=A+B\),那么\(S\)一定可以表示为\(S=y\times{cir_{min}}\)。对于字符串上\(\forall x\)点推导可得$x=k $$\times S$$+|A|=k$$ \times{cir_{min}}\times{y}$$ + |A|$ ,其中,\(|A|\)\(\in\)[\(k\times{cir_{min}}\), \((k + 1)\times cir_{min}]\),分离变量,得只需满足\(\exists y\in Z^{+} and \in [\frac{x}{(k+1)\times cir_{min}}, \frac{x}{k\times cir_min}]\),即是答案中的\(1\)
$click$ $for$ $codes$
# include "bits/stdc++.h"
using namespace std;
char str[(int)1e6 + 3];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, k;
while(~scanf("%d%d", &n, &k)) {
/*
HINT: there exits a strange problem, which I guess results from the OJ
The title is guaranteed to be a single group of data, but if it is normally processed as a single group, there will be no output on the platform, even if everything is normal locally. The following feedback will be given to us : 'wrong answer Unexpected EOF in the participants output'.
I was really surprised. After trying to change the language ( c++20 -> c++17 -> c++1 ), change bool to int... I had to query related questions online. I found that one blogger proposed the above solution, which was found to be effective in practice.
If we encounter such problem in the future, perhaps we can solve them in the same way :)
*/
scanf("%s", str + 1); // well, it's a pity that (cin >> str + 1) will be judged wrong, even on CF
int len = strlen(str + 1);
int j = 0;
vector<int> nxt(len + 1);
for(int i = 2; i <= len; ++i) { // find nxt array in KMP to make use of its properties
while(j && str[i] != str[j + 1]) j = nxt[j];
if(str[i] == str[j + 1]) ++j;
nxt[i] = j;
}
for(int i = 1; i <= len; ++i) {
int cir = i - nxt[i]; // cir := minimum cyclic joint
auto check = [&](int x, int cir) -> bool {
double L = (double) x / (double) ((double)(k + 1) * (double)cir); // infimum
double R = (double) x / (double) ((double)k * (double)cir); // supremum
return floor(R) >= ceil(L);
};
cout << check(i, cir);
}
cout << endl;
}
return 0;
}
本题还牵扯到一种名为\(Z算法\)的字符串算法,我不知道会不会去学一学,也许会,也许不会,就像宿舍门口有两棵树,一棵不是朴树,另一棵不是春上春树