题解Atcoder ABC300 F.More Holidays(线性做法)
Posted linyihdfj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解Atcoder ABC300 F.More Holidays(线性做法)相关的知识,希望对你有一定的参考价值。
F.More Holidays
题目描述:
给你一个由 o
和 x
组成的长度为 \\(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 abc256全题解(区间合并模板矩阵快速幂优化dp线段树……)
AtCoder abc256全题解(区间合并模板矩阵快速幂优化dp线段树……)
AtCoder Beginner Contest 121 题解