1455F String and Operations(思维+贪心)
Educational Codeforces Round 99 (Rated for Div. 2)
F. String and Operations
题意:给一个长度为 n n n 的字符串 s s s,其中只包含前 k k k 个小写字母。现在需要对字符串进行 n n n 次操作,第 i i i 次操作的操作对象是初始位于位置 i i i 的对应字符,共有 5 5 5 种操作:
- 与上一个字符(如果存在)进行交换
- 与下一个字符(如果存在)进行交换
- 将该字符循环移动到下一个字符, a → b , b → c , . . . , ( a + k − 1 ) → a a \rightarrow b, b \rightarrow c, ...,(a+k-1) \rightarrow a a→b,b→c,...,(a+k−1)→a
- 将该字符循环移动到上一个字符, c → b , b → a , a → ( a + k − 1 ) c \rightarrow b, b \rightarrow a,a \rightarrow (a+k-1) c→b,b→a,a→(a+k−1)
- 不操作
求经过 n n n 次操作后能得到的最小字典序的字符串。
范围: 1 ≤ n ≤ 500 , 2 ≤ k ≤ 26 1 \le n \le 500, 2 \le k \le 26 1≤n≤500,2≤k≤26。
分析: 要让字典序最小,必须保证前面的字符尽可能小,经过简单分析可以发现,当前位置字符的最优解可以从以下几种情况中构造而来:
设前一个位置的字符为 p r e pre pre,当前位置字符为 x x x,下一个位置的字符为 n x t nxt nxt,下下个位置的字符为 n n x t nnxt nnxt。
① b e s t ( x ) + a n s [ i + 1 , n ] best(x)+ans[i+1, n] best(x)+ans[i+1,n]
② b e x t ( n x t ) + x + a n s [ i + 2 , n ] bext(nxt)+x+ans[i+2, n] bext(nxt)+x+ans[i+2,n]
③ n x t + b e s t ( x ) + a n s [ i + 2 , n ] nxt+best(x)+ans[i+2, n] nxt+best(x)+ans[i+2,n]
④ n n x t + b e s t ( x ) + n x t + a n s [ i + 3 , n ] nnxt+best(x)+nxt+ans[i+3, n] nnxt+best(x)+nxt+ans[i+3,n]
其中 b e s t ( x ) best(x) best(x) 表示字符 x x x 与 x x x 相邻字符中的最小字典序字符。
通过以上 4 4 4 种情况取最优解则可以保证当前 i i i 位置的字典序尽可能小,但是引出了另外一个问题,在处理第 i i i 个字符时有可能前一个位置的字符字典序并不是最小,前一个位置的最优解可以从以下几种情况中构造而来:
① p r e + a n s [ i , n ] pre+ans[i, n] pre+ans[i,n]
② x + p r e + a n s [ i + 1 , n ] x+pre+ans[i+1, n] x+pre+ans[i+1,n]
③ n x t + p r e + x + a n s [ i + 2 , n ] nxt+pre+x+ans[i+2, n] nxt+pre+x+ans[i+2,n]
注意在处理到 x x x 的时候,之前的所有字符一定无法继续操作了,因此不需要 b e s t best best,并且这里几种情况只涉及要位置的移动,对 x x x 和 n x t nxt nxt 也不需要进行 b e s t best best。
通过以上的逻辑,先判断前一个位置的字符是否可以优化,能优化就优化,不能优化就尝试优化当前位置的字符。
时间复杂度 O ( n ) O(n) O(n)。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 500 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
string str, ans;
char D(char c)
{
return 'a' + ((c - 'a') - 1 + k) % k;
}
char U(char c)
{
return 'a' + ((c - 'a') + 1) % k;
}
char best(char c)
{
return min(c, min(D(c), U(c)));
}
signed main()
{
int T = read();
while (T--)
{
n = read(), k = read();
cin >> str;
ans = "";
int idx = 0;
while (idx < n)
{
ans += str[idx];
if (idx - 1 >= 0)
{
char pre = ans[idx - 1];
int res = 0;
if (ans[idx] < ans[idx - 1])
{
ans[idx - 1] = ans[idx];
res = 1;
}
if (idx + 1 < n && str[idx + 1] < ans[idx - 1])
{
ans[idx - 1] = str[idx + 1];
ans += str[idx];
res = 2;
}
if (res) ans[idx] = pre;
if (res == 1)
{
idx++;
continue;
}
else if(res == 2)
{
idx += 2;
continue;
}
}
ans[idx] = best(ans[idx]);
int res = 0;
if (idx + 1 < n && best(str[idx + 1]) < ans[idx])
{
if (best(str[idx + 1]) == str[idx + 1])
{
ans += str[idx + 1];
swap(ans[idx], ans[idx + 1]);
}
else
{
ans[idx] = best(str[idx + 1]);
ans += str[idx];
}
res = 1;
}
if (idx + 2 < n && str[idx + 2] < ans[idx])
{
while (ans.length() < idx + 3) ans += 'a';
ans[idx] = str[idx + 2];
ans[idx + 1] = best(str[idx]);
ans[idx + 2] = str[idx + 1];
res = 2;
}
if (res == 0) idx++;
else if (res == 1) idx += 2;
else idx += 3;
}
cout << ans << endl;
}
return 0;
}
【END】感谢观看