CF1700F Puzzle 解题报告

CF1700F Puzzle 解题报告

CF1700F Puzzle - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Problem - 1700F - Codeforces

题意

给定两个2×n01 矩阵 AB,定义一次操作为交换 A 中任意两个相邻的位置中的值,输出使得 A=B的最小操作次数,如果无法使A=B 则输出 1

Sol

AB都只有一行,则答案就是|sumi|sumi为前i个位置AiBi的前缀和)。

推广到2行,因为题目没有要求交换次序,所以我们可以从数组起始往后递推。

若将(0,i)1挪下去,则sum0,i=1,sum1,i+=1

可以想到,若sum0,isum1,i同号,那么这次交换是不需要的,可以放到i+1处进行。

而若sum0,isum1,i异号,我们交换k=min(sum0,i,sum1,i)次,节省了k次。

因为题目中没有说一定要上下或左右交换,所以我们以上是进行了上下交换,即把原本 suma0,i>sumb0,isuma1,i<sumb1,isuma0,i<sumb0,isuma1,i>sumb1,i 的两波左右交换用一波上下交换代替,推广到k,就是用k次上下交换代替了2k次左右交换。

而若以上操作不如左右交换优秀,那么在后面会再进行k次上下交换以补救。恰好最终贡献还是2k,思想类似于 反悔自动机的差值相消思想

要注意这道题虽然 看起来人畜无害 ,但也是得开longlong的,因为中间的累加约等于n2

Code

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int MN = 4e5 + 5;

int n;
int a[2][MN], b[2][MN], dp[2][MN];

signed main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n;
    int sum = 0;
    for (int i = 0; i <= 1; ++i)
        for (int j = 1; j <= n; ++j) cin >> a[i][j], sum += a[i][j];
    for (int i = 0; i <= 1; ++i)
        for (int j = 1; j <= n; ++j) cin >> b[i][j], sum -= b[i][j];
    if (sum != 0) {
        puts("-1");
        return 0;
    }
    int sum1 = 0, sum2 = 0;
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        sum1 += a[0][i] - b[0][i];
        sum2 += a[1][i] - b[1][i];
        if (sum1 < 0 && sum2 > 0) {
            int k = min(-sum1, sum2);
            ans += k;
            sum1 += k, sum2 -= k;
        }
        else if (sum1 > 0 && sum2 < 0) {
            int k = min(sum1, -sum2);
            ans += k;
            sum1 -= k, sum2 += k;
        }
        ans += abs(sum1) + abs(sum2);
    }
    cout << ans << '\n';
    return 0;
}
posted @   zjsqwq  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示