AtCoder ABC 346 D - 超详多解法C++官方及非官方题解 (含代码)

一.问题描述(中英文)

1.英文

Problem Statement: You are given a string S of length N consisting of 0 and 1. A string T of length N consisting of 0 and 1 is a good string if and only if it satisfies the following condition: There is exactly one integer i such that 1≤i≤N−1 and the i-th and (i+1)-th characters of T are the same. For each i=1,2,…,N, you can choose whether or not to perform the following operation once: If the i-th character of S is 0, replace it with 1, and vice versa. The cost of this operation, if performed, is Ci. Find the minimum total cost required to make S a good string. Constraints 2≤N≤2×10^5 S is a string of length N consisting of 0 and 1. 1≤Ci≤10^9 N and Ci are integers.

2.中文

问题陈述: 给定一个长度为N的字符串S,由0和1组成。 一个长度为N的字符串T是一个好字符串,当且仅当它满足以下条件: 存在一个整数i,使得1≤i≤N−1,并且T的第i个字符和第(i+1)个字符相同。 对于每个i=1,2,…,N,你可以选择是否执行以下操作一次: 如果S的第i个字符是0,则将其替换为1,反之亦然。如果执行此操作,则操作的成本为Ci。 找到使S成为好字符串所需的最小总成本。

约束条件: 2≤N≤2×10^5 S是一个长度为N的由0和1组成的字符串。 1≤Ci≤10^9 N和Ci是整数。

二.ChatGPT题解

这个问题可以通过动态规划(Dynamic Programming, DP)来解决。我们可以定义一个状态dp[i][0]表示将S的前i个字符变为好字符串且第i个字符为0的最小总成本,以及一个状态dp[i][1]表示将S的前i个字符变为好字符串且第i个字符为1的最小总成本。

接下来我们可以按照以下步骤来解决这个问题:

  1. 初始化dp数组为一个较大的值,表示初始状态。

  2. 对于i从1到N,分别计算dp[i][0]和dp[i][1]。

  3. 对于dp[i][0],有两种情况:

    • 如果S的第i个字符为0,则dp[i][0] = min(dp[i-1][0], dp[i-1][1] + Ci)。

    • 如果S的第i个字符为1,则dp[i][0] = dp[i-1][0]。

  4. 对于dp[i][1],有两种情况:

    • 如果S的第i个字符为1,则dp[i][1] = min(dp[i-1][1], dp[i-1][0] + Ci)。

    • 如果S的第i个字符为0,则dp[i][1] = dp[i-1][1]。

  5. 最终答案为min(dp[N][0], dp[N][1])。

下面是C++的实现代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N;
    cin >> N;
    string S;
    cin >> S;
    vector<int> C(N);
    for (int i = 0; i < N; ++i) {
        cin >> C[i];
    }

    vector<vector<long long>> dp(N+1, vector<long long>(2, 1e18));
    dp[0][0] = dp[0][1] = 0;

    for (int i = 1; i <= N; ++i) {
        if (S[i-1] == '0') {
            dp[i][0] = min(dp[i-1][0], dp[i-1][1] + C[i-1]);
        } else {
            dp[i][0] = dp[i-1][0];
        }

        if (S[i-1] == '1') {
            dp[i][1] = min(dp[i-1][1], dp[i-1][0] + C[i-1]);
        } else {
            dp[i][1] = dp[i-1][1];
        }
    }

    cout << min(dp[N][0], dp[N][1]) << endl;

    return 0;
}

这段代码会读取输入的字符串S和对应的成本数组C,然后计算出使S成为好字符串所需的最小总成本,并输出结果。

三.官方题解(1)

1.原文

Fix an i such that the i-th and (i+1)-th characters of T coincide. Then, the 1-st through i-th and the (i+1)-th through N-th characters form ...0101010101..., strings where 0 and 1 appears alternately.

Thus, it is sufficient to find the following values for each i:

The minimum total cost required to make the 1-st through i-th characters of S 01010101..., which starts with 0 and has alternating 0 and 1.

The minimum total cost required to make the 1-st through i-th characters of S 10101010..., which starts with 1 and has alternating 0 and 1.

The minimum total cost required to make the (i+1)-st through N-th characters of S ...10101010, which ends with 0 and has alternating 0 and 1.

The minimum total cost required to make the (i+1)-st through N-th characters of S ...01010101, which ends with 1 and has alternating 0 and 1.

For the former two, the results for (i+1) can be easily obtained from the result for i, so they can be filled in ascending order of i; for the latter two, those for (i−1) from those for i, so they can be filled in descending order of i.

For example, we introduce how the first value is computed.

The (i+1)-th character must be made 0 if (i+1) is odd, and 1 if even; if no modification is needed to do so, the result for i and that for (i+1) coincides. Otherwise, one can add C i+1​to the result for i to obtain that for (i+1).

When implementing, instead of considering strings ending with 0 or 1, one can think about a string whose even-positioned characters (among the whole N characters) are 0 and even-positioned ones are 1, and vice versa, in order to reduce trouble.

2.中文

修复一个i,使得T的第i个和第(i+1)个字符重合。接着,第1到第i个字符和第(i+1)到第N个字符形成...0101010101...的字符串,其中0和1交替出现。

因此,对于每个i,我们需要找到以下值:

使S的前1到i个字符变为01010101...,以0开头并且0和1交替出现的最小总成本。

使S的前1到i个字符变为10101010...,以1开头并且0和1交替出现的最小总成本。

使S的第(i+1)到N个字符变为...10101010,以0结尾并且0和1交替出现的最小总成本。

使S的第(i+1)到N个字符变为...01010101,以1结尾并且0和1交替出现的最小总成本。

对于前两个情况,可以通过i的结果轻松获得(i+1)的结果,因此可以按照i的升序填充;对于后两个情况,可以通过(i-1)的结果获得i的结果,因此可以按照i的降序填充。

例如,我们介绍如何计算第一个值。

如果(i+1)是奇数,则(i+1)的字符必须变为0,如果是偶数,则变为1;如果不需要修改,则i的结果和(i+1)的结果相同。否则,可以将Ci+1添加到i的结果中,得到(i+1)的结果。

在实现时,可以考虑以0开头并且偶数位置为0,奇数位置为1的字符串,以及以1开头并且偶数位置为1,奇数位置为0的字符串,以简化问题。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    int n;
    cin >> n;
    string s;
    cin >> s;
    vector<ll> c(n);
    for (int i = 0; i < n; i++) cin >> c[i];
    vector<ll> f0(n + 1), f1(n + 1), g0(n + 1), g1(n + 1);
    for (int i = 0; i < n; i++) {
        f0[i + 1] = f0[i];
        f1[i + 1] = f1[i];
        if (i % 2 == 0) {
            if (s[i] == '0') f1[i + 1] += c[i];
            else f0[i + 1] += c[i];
        }
        else {
            if (s[i] == '0') f0[i + 1] += c[i];
            else f1[i + 1] += c[i];
        }
    }
    for (int i = n - 1; i >= 0; i--) {
        g0[i] = g0[i + 1];
        g1[i] = g1[i + 1];
        if (i % 2 == 0) {
            if (s[i] == '0') g0[i] += c[i];
            else g1[i] += c[i];
        }
        else {
            if (s[i] == '0') g1[i] += c[i];
            else g0[i] += c[i];
        }
    }
    ll ans = 1'000'000'000'000'000'000;
    for (int i = 1; i < n; i++) ans = min(ans, f0[i] + g0[i]);
    for (int i = 1; i < n; i++) ans = min(ans, f1[i] + g1[i]);
    cout << ans << '\n';
}

原题地址:D - Gomamayo Sequence (atcoder.jp)

  • 31
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值