D. Diverse Garland
https://codeforces.com/problemset/problem/1108/D
题意:给定n个字符,他们是环状的,每个字符是RGB的其中一个。现在要将字符改变为其他颜色,问最少操作多少次,可以让相邻的字符没有相同的颜色。
思路:动态规划,考虑当前位置字符为RGB中的其中一个时,前面所有相邻字符都不相等的最小操作次数。状态转移就是从上一个状态的不相同的两种字符中,选取代价较小的一个。最后,再回溯即可。
总结:在状态回溯的时候,需要增加判定,保证当前位置与之前的字符不要相同。
有个疑问,既然是环状的,也没有加首尾特判,怎么就ac了啊。。
是因为没注意到这句话:In other words, if the obtained garland is t
then for each i
from 1
to n−1
the condition ti≠ti+1
should be satisfied.
inline void solve() {
int n;
cin >> n;
string s;
cin >> s;
for (auto& c : s) {
switch(c){
case('R'):
c = '0';
break;
case('G'):
c = '1';
break;
case('B'):
c = '2';
break;
}
}
vector<array<int, 3>> dp(n, {INF, INF, INF});
{
dp[0] = {1, 1, 1};
dp[0][s[0] - '0'] = 0;
}
for (int i = 1; i < n; ++i) {
for (int j = 0; j < 3; ++j) {
int u = (j + 1) % 3;
int v = (j + 2) % 3;
if (j == s[i] - '0') {
dp[i][j] = min(dp[i - 1][u], dp[i - 1][v]);
}
else {
dp[i][j] = min(dp[i - 1][u], dp[i - 1][v]) + 1;
}
}
}
vector<int> pos;
pos.reserve(n);
int g = min_element(dp[n - 1].begin(), dp[n - 1].end()) - dp[n - 1].begin();
pos.push_back(g);
for (int i = n - 2; i >= 0; --i) {
auto p = pos.back();
for (int j = 0; j < 3; ++j) {
if (j == p) {
continue;
}
if (dp[i][j] == dp[i + 1][p] - (s[i + 1] - '0' != p)) {
pos.push_back(j);
break;
}
}
}
cout << dp[n -1][g] << '\n';
while (!pos.empty()) {
char c;
switch(pos.back()) {
case(0):
c = 'R';
break;
case(1):
c = 'G';
break;
case(2):
c = 'B';
break;
}
cout << c;
pos.pop_back();
}
}

浙公网安备 33010602011771号