1 条题解
-
0njnu19210225 (季润民) LV 10 MOD @ 2023-07-03 13:51:42
题解
想要有解,必须满足 \(1\) 的数量与 \(0\) 的数量的差的绝对值 \(\le 1\).
那么如果给定字符串 \(0\) 的数量大于 \(1\) 的数量,最后结果即应为 \("0101...0"\);那么如果给定字符串 \(1\) 的数量大于 \(0\) 的数量,最后结果即应为 \("1010...1"\);如果数量相等,最后结果为 \("0101...01"\) 或者 \("1010...10"\),选择两种操作次数中最小的即可。
现在问题就转化成了,给定初始字符串 \(s\) 和目标字符串 \(t\) ,如何只通过交换在最小次数内由 \(s\) 变为 \(t\) .
可以发现,一次交换操作会将一个字符移动一个位置,如果想把一个字符从位置 \(i\) 移动到 \(j\),那么所需要交换的次数即为 \(abs(i-j)\).
将所有 \(1\) 移动到对应位置后,所有 \(0\) 自然也移动到对应位置了,所以只需要每个\(1\)的 \(abs(i-j)\)并将其求和即可。
那么如何选择对应的位置使得结果最小呢?按顺序对应即可,也就是 \(s\) 中第一个 \(1\) 的位置要移动到的位置为 \(t\) 中第一个 \(1\) 的位置, \(s\) 中第二个 \(1\) 的位置要移动到的位置为 \(t\) 中第二个 \(1\) 的位置...
示例代码
typedef long long LL; LL trans(string s, string t) { int i=0, j=0; LL res = 0; for(int i=0; i<s.size(); i++) { while(j<t.size() && t[j] != '1') j++; if(s[i] == '1') { res += abs(i-j); j++; } } return res; } void Solve() { string str; cin >> str; int zero = 0; int one = 0; int n = str.size(); for(int i=0; i<n; i++) { if(str[i] == '0') zero++; else one++; } string tar; LL res; if(zero == one) { for(int i=0; i<n/2; i++) tar += "10"; res = trans(str, tar); reverse(tar.begin(), tar.end()); res = min(res, trans(str, tar)); } else if(zero > one) { for(int i=0; i<n/2; i++) tar += "01"; tar.push_back('0'); res = trans(str, tar); } else { for(int i=0; i<n/2; i++) tar += "10"; tar.push_back('1'); res = trans(str, tar); } cout << res << endl; }
- 1
信息
- ID
- 1421
- 难度
- 6
- 分类
- (无)
- 标签
- (无)
- 递交数
- 36
- 已通过
- 12
- 通过率
- 33%
- 上传者