ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CodeForces 526D Om Nom and Necklace

2022-06-22 11:36:16  阅读:119  来源: 互联网

标签:Nom Om nxt int dfrac len fail maxn Necklace


洛谷传送门

CF 传送门

思路

题意相当于将 \(S\) 表示成 \(A^kB\)(\(A^x = A^{x-1}A\),\(A^0\) 为空串),其中 \(B\) 为 \(A\) 的前缀。

考虑枚举 \(|A^k|\),设 \(|A^k| = len\ (k\ |\ len)\),在 \([1,len]\) 中寻找长度为 \(\dfrac{len}{k}\) 的循环节。看到循环节就想到 KMP,预处理出 \(fail_i\),那么 \([1,len]\) 的最短的循环节长度为 \(len - fail_{len}\)。当 \(len - fail_{len} \nmid len\) 或者 \(len < 2 \cdot (len - fail_{len})\)(即循环次数 \(< 2\);注意当 \(m=1\) 时这个条件可以不满足),则 \([1,len]\) 不存在循环节。现在已经知道了最短的循环节长度为 \(len - fail_{len}\),若 \([1,len]\) 存在长度为 \(\dfrac{len}{k}\) 的循环节,那么必须满足 \((len - fail_{len})\ |\ \dfrac{len}{k}\)。

现在要求最长的满足 \(B\) 为 \(A\) 前缀的 \(B\) 的长度。先求出原串的 \(\mathbf{Z}\) 函数数组 \(z\)。显然 \(B\) 也必须是整个串的前缀,所以 \(|B| \le z_{len + 1}\)。又因为 \(|B| \le |A| = \dfrac{len}{k}\),所以 \(|B|_{\max} = \min(z_{len+1},\dfrac{len}{k})\)。知道了 \(|B|\) 的范围,也就知道了满足条件的整个串的前缀的范围。开一个数组 \(d_i\),若 \(d_i > 0\) 则原串前缀 \([1,i]\) 满足条件,否则不满足,在 \(d\) 数组上将 \([i,i+|B|_{\max}]\) 整体加一。实现时差分即可。

时空复杂度均为 \(O(n)\)。

代码

code
/*

p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second

using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;

const int maxn = 1000100;

int n, m, nxt[maxn], fail[maxn], d[maxn];
char s[maxn];

void solve() {
	scanf("%d%d%s", &n, &m, s + 1);
	nxt[1] = n;
	for (int i = 2, l = 0, r = 0; i <= n; ++i) {
		nxt[i] = (i > r) ? 0 : min(nxt[i - l + 1], r - i + 1);
		while (s[nxt[i] + 1] == s[nxt[i] + i]) {
			++nxt[i];
		}
		if (i + nxt[i] - 1 > r) {
			l = i;
			r = i + nxt[i] - 1;
		}
	}
	for (int i = 2, j = 0; i <= n; ++i) {
		while (j && s[i] != s[j + 1]) {
			j = fail[j];
		}
		if (s[i] == s[j + 1]) {
			++j;
		}
		fail[i] = j;
	}
	for (int i = m; i <= n; i += m) {
		// printf("fail: %d\n", i - fail[i]);
		if (i % (i - fail[i]) || (i - fail[i]) * min(m, 2) > i || (i / m) % (i - fail[i])) {
			continue;
		}
		++d[i];
		--d[i + min(i / m, nxt[i + 1]) + 1];
		// printf("%d %d\n", i / m, nxt[i + 1]);
	}
	for (int i = 1; i <= n; ++i) {
		d[i] += d[i - 1];
		printf("%d", min(d[i], 1));
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:Nom,Om,nxt,int,dfrac,len,fail,maxn,Necklace
来源: https://www.cnblogs.com/zltzlt-blog/p/16399805.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有