1 条题解
-
0
自动搬运
来自洛谷,原作者为

szh_AK_all
S挂分挂到被洛谷7级勾卡线|I can do all things搬运于
2025-08-24 22:55:21,当前版本为作者最后更新于2024-02-17 20:32:38,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题意
我们需要进行若干次操作,使得字符串 的顺序对数量最大。每次操作可以将 中相邻的两个值取反。
分析
由于 只包含 和 ,所以为了使顺序对数量最大,我们尽可能将 放在末尾,将 尽可能放在前面。可以发现,经过操作后, 或 的数量会发生改变。所以,这也为我们后续的操作奠定了基础。
首先,我们将问题简化:我们可以让字符串 末尾有任意数量的 ,开头有任意数量的 ,那么我们该如何分配 和 的数量,使得顺序对数量最大呢?
相信大家都明白这个道理吧:在周长相等的正方形与长方形中,正方形面积总比长方形大。为什么?因为正方形的边长相等,也就是差值为 。
转换为数学逻辑就是: 与 相比(,为了方便起见,设 ),若 ,则 ;反之同理。
举个例子:若 的长度为 ,则最优情况下 中有两个 ,三个 ,或者有三个 ,两个 。
清楚这个问题后,再来考虑题目。我们要尽可能让 靠后, 考前,且 的数量与 的数量相差小,则我们由字符串的末尾像中间枚举,若枚举到的字符为 ,则使用一次操作;同理,再由字符串的开头像中间枚举,若枚举到的字符为 ,则使用一次操作。
枚举 的情况时若枚举到的字符为 ,则使用一次操作,为什么这样可以保证字符串从中间到末尾都为 呢?假设该字符前一个字符为 ,则两全其美,这两个字符都变为了 ;若前一个字符为 ,则在操作之后,前一个字符变为 ,但是不用担心,因为在下一轮的枚举中前一个字符又会变为 。
Code
#include <bits/stdc++.h> using namespace std; int ans, a[200005]; int main() { string s; cin >> s; int n = s.size(); for (int i = n - 1; i >= n / 2; i--) { if (s[i] == '0') { a[++ans] = i; s[i] = '1'; if (s[i - 1] == '0') s[i - 1] = '1'; else s[i - 1] = '0'; } } for (int i = 0; i < n / 2; i++) { if (s[i] == '1') { a[++ans] = i + 1; s[i] = '0'; if (s[i + 1] == '0') s[i + 1] = '1'; else s[i + 1] = '0'; } } long long o = 0; for (int i = 0; i < n; i++) if (s[i] == '1') o++; long long tmp = 0; for (int i = 0; i < n; i++) { if (s[i] == '0') tmp += o; else o--; } cout << tmp << endl << ans << endl; for (int i = 1; i <= ans; i++) cout << a[i] << " "; }打字不易,请管理大大通过吧!也请各位点个赞!
另外附上赛事记录
- 1
信息
- ID
- 9799
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者