一.问题描述(中英文)
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的最小总成本。
接下来我们可以按照以下步骤来解决这个问题:
初始化dp数组为一个较大的值,表示初始状态。
对于i从1到N,分别计算dp[i][0]和dp[i][1]。
对于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\]。
对于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\]。
最终答案为min(dp[N][0], dp[N][1])。
下面是C++的实现代码:
cpp
#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+1to 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的字符串,以简化问题。
cpp
#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';
}