第二题:COWNTACT TRACING 2
标签:思维、枚举、模拟
题意:给定长度为nnn的字符串(只包含010101),求用初始最少的111,每天每一个111都会把相邻的两个位置都变成111,经过若干天后形成给定的这个字符串。(1<=n<=3∗1051<=n<=3*10^51<=n<=3∗105)
我们通过样例解释一下,比如要形成长度为555的111111111111111字符串。
可以一开始在第三个位置放001000010000100,第一天:011100111001110,第二天:111111111111111,所以初始只要一个111。
题解:比较容易想到我们需要把连续的111的个数拆出来。比如000111011011110010001110110111100100011101101111001=> 3 2 4 13 \ 2 \ 4 \ 13 2 4 1
首先我们去思考每一团连续的111要形成的最多天数是多少?(为什么是最多天数呢,因为天数越多,初始的111就越少)不好想的话,那我们举几个例子:
111:000天
111111:000天(这里可能有些人会有疑惑,其实中间部分的和左右两边的情况 我们到时候要分类讨论的,这边姑且先考虑中间部分的)
111111111:111天
111111111111:111天
111111111111111:222天
111111111111111111:222天
..................
往下不断推下去,能推出最多天数其实是不是就是1的个数减去111,再除以222。(其实就是从最中间往外扩散的过程)
这是每一团连续的111要形成的最多天数,那么我们要让每一团的符合,得去拿每一团的最多天数中的最小值(minDayminDayminDay),让每一团连续的111都满足天数要求。
因为每一团要让天数往下降,很简单,只要让初始的111多一点就好了。
在求出minDayminDayminDay的基础上,我们接下来就是去求每一团在这样一个天数下,需要初始的111的个数。
举个例子:比如minDay=2minDay=2minDay=2,某一团连续的111是111111111111111111111,那么我们初始的111应该是001010000101000010100
这道题还有个需要注意的点是:最左(111)和最右(nnn)连续的111具有特殊性,最大天数能到达这一团的111的个数减一。因为如果最左设置111,往左扩散是会碰墙,过不去的;最右同理。
代码:
#include <bits/stdc++.h>
using namespace std;
vector<int> v;
int main() {
int n;
string s;
cin >> n >> s;
int pre = 0, suf = n - 1, cnt = 0, minDay = n + 1;
while (s[pre] == '1') pre++;
while (suf > pre && s[suf] == '1') suf--;
if (pre != 0) {
v.push_back(pre);
minDay = min(minDay, pre - 1);
}
if (suf != n - 1) {
v.push_back(n - 1 - suf);
minDay = min(minDay, n - 2 - suf);
}
for (int i = pre; i <= suf; i++) {
if (s[i] == '1') cnt++;
else if (s[i] == '0') {
if (cnt > 0) {
v.push_back(cnt);
minDay = min(minDay, (cnt - 1) / 2);
}
cnt = 0;
}
}
if (cnt > 0) {
v.push_back(cnt);
minDay = min(minDay, (cnt - 1) / 2);
}
int ans = 0;
for (int i = 0; i < v.size(); i++) {
int k = v[i] / (minDay * 2 + 1);
if (v[i] % (minDay * 2 + 1)) k++;
ans += k;
}
cout << ans;
return 0;
}
文章描述了一道编程题目,涉及如何在有限天数内通过每次将相邻的1变为1来形成给定的字符串,如11111。通过分析连续1的团最多需要的天数并确定初始1的最少数量,给出了一个基于C++的解决方案。
2774

被折叠的 条评论
为什么被折叠?



