题解Atcoder ABC300 F.More Holidays(线性做法)

Posted linyihdfj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解Atcoder ABC300 F.More Holidays(线性做法)相关的知识,希望对你有一定的参考价值。

【题解】Atcoder ABC300 F.More Holidays(线性做法)

F.More Holidays

题目描述:

给你一个由 ox 组成的长度为 \\(N\\) 的字符串 \\(S\\),以及整数 \\(M\\)\\(K\\)。保证 \\(S\\) 至少包含一个 x

假设 \\(T\\) 是由 \\(S\\) 复制 \\(M\\) 次而成的长度为 \\(NM\\) 的字符串。考虑将 \\(T\\) 中的 \\(K\\)x 恰好替换为 o

你的目标是在替换后的 \\(T\\) 中有尽可能长的由 o 组成的连续子串。

找出在替换后由 o 组成的连续子串的最大长度。

题目分析:

提供一种线性做法。

仿佛见过一道类似的题,不确定是不是就是这道。

考虑我们最后得到的极长连续的 o 串,一定是形如:(\\(S\\) 的一段后缀) + (若干个完整的 \\(S\\)) + (\\(S\\) 的一段前缀)

对于若干个完整的 \\(S\\) 我们可以直接求出来它的个数,设 \\(tot\\)\\(S\\)x 的个数则中间完整 \\(S\\) 的个数就是 \\(\\lfloor \\fracktot \\rfloor\\)

而对于 \\(S\\) 的一段后缀 + \\(S\\) 的一段前缀,我们可以考虑把他们拼在一起,也就是将 \\(S\\) 变成 \\(SS\\) 即二倍字符串长度,这样我们发现 \\(SS\\) 的任意一个子串都可以表示为上述形式,但是任意的上述形式就是 \\(SS\\) 的某一子串嘛?

其实不一定吧,因为我们上述的形式其实并不完整,因为我们可能连一整段都取不到所以可能最后取到的极长字串就是 \\(S\\) 内的一段区间,但是这样会发现虽然不完全,但是我们依旧可以对于 \\(S\\) 的每一个子串找到 \\(SS\\) 中的一个子串使得他们相等,所以就没有什么问题。

解决这个问题,一个想法就是直接枚举左端点,然后右端点就可以二分取得。

但是你会发现二分右端点是一个很傻的行为,因为随着左端点的增加右端点单调不降,所以可以直接使用双指针优化到 \\(O(n)\\)

需要注意的细节就是:有 \\(m\\) 个的限制所以可能我们没办法取得 (\\(S\\) 的一段后缀) + (\\(S\\) 的一段前缀)。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6+5;
char s[N];
int pre[N];
signed main()
	int n,m,k;scanf("%lld%lld%lld",&n,&m,&k);
	scanf("%s",s+1);
	for(int i=1; i<=n; i++)	s[i+n] = s[i];
	for(int i=1; i<=2 * n; i++)	pre[i] = pre[i-1] + (s[i] == \'x\');
	int ans = k / pre[n] * n,tmp = 0;
	m -= k / pre[n];
	k = k % pre[n];
	for(int l=1,r = 1; l<=n; l++)
		while(r + 1 <= 2 * n && pre[r + 1] <= k + pre[l-1]) ++r;
		if(m == 1)	tmp = max(tmp,min(r,n) - l + 1);
		else if(m > 1)	tmp = max(tmp,r - l + 1);
	
	printf("%lld\\n",ans + tmp);
	return 0;

以上是关于题解Atcoder ABC300 F.More Holidays(线性做法)的主要内容,如果未能解决你的问题,请参考以下文章

题解 [Atcoder ABC 161] A,B,C

AtCoder abc256全题解(区间合并模板矩阵快速幂优化dp线段树……)

AtCoder abc256全题解(区间合并模板矩阵快速幂优化dp线段树……)

AtCoder Beginner Contest 121 题解

AtCoder Beginner Contest 298 题解

AT_abc106_d [ABC106D] AtCoder Express 2 题解