1 条题解
-
0
首先有一个结论:若 ,交换 和 且不改变它们中间的字符的代价为 。
首先,答案的下界显然为 ,因为即使不管中间字符的顺序,也要进行这么多次操作。现在只需要证明一定能在 次操作内完成即可。
对于 的情况,显然成立;现在考虑 的情况。若 ,我们可以先交换 和 ,再递归地考虑交换 和 即可;否则一定有 ,先递归地考虑交换 和 ,再交换 和 即可。
由于每次操作都会将 减少 ,总操作次数即为 。
假如没有上取整,这显然是好做的:对于每一个 的 ,若存在一个还没有被匹配过的 满足 且 ,任选一个 进行匹配即可,容易证明任何选择的答案都是相同且最优的;否则继续往后找,等待后面的数将其匹配。
现在有了上取整,可以发现,如果 不为 ,其值越小,损失越大,因为同样次数的交换还可以在多走 格。既然这样,在上面的过程中,我们不如选 较大的 ,从而减少损失的值。
实现的时候,记录两个
set<pair<int, int>>,分别代表 或 时符合条件的还没有被匹配的 的 和下标。使 为 或尽量大的 即为第一个 大于等于 的 。若找不到,则为 最小的一个 。AC 代码如下:
#include <bits/stdc++.h> using namespace std; int n, k; string s, t; set<pair<int, int>> st[2]; long long ans; int main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> k >> s >> t; for (int i = 0; i < n; i++) { if (s[i] == t[i]) continue; int vl = s[i] - '0'; if (st[vl].empty()) { st[!vl].insert({i % k, i}); continue; } auto it = st[vl].lower_bound({i % k, 0}); if (it == st[vl].end()) it = st[vl].begin(); ans += ceil(1.0 * (i - (it -> second)) / k); st[vl].erase(it); } cout << ans; return 0; }
- 1
信息
- ID
- 7601
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 19
- 已通过
- 8
- 上传者