题目大意
有一个长度为 n 的字符串和一个整数 k ( k < n ) ,有下列两种操作:
- 交换“相隔一个字符”的两个字符。
- 选取连续的 k 个字符,将它们的顺序反转。
每次操作二选一,你可以进行无限制次数(可以为零次)的操作。
请找出最终能得到的字典序最小的字符串。
思路
- 操作 1 可以将字符串中奇数位和偶数位的字符分别排序。
- 对于操作 2 ,当 k 为偶数时,在奇(偶)数位的字符可以去到偶(奇)数位,然后利用操作 1 ,可以使得所有字符整体排序;而当 k 为奇数时,在奇(偶)数位的字符依然会留在奇(偶)数位,那么就无法进行奇偶数位置之间的流动,无法整体排序。
代码
- 当 k 为奇数时,将字符串中奇数位和偶数位的字符分别排序。
- 当 k 为偶数时,对字符串整体排序即可。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
string s;
cin >> s;
if (k & 1)
{
string s1 = "", s2 = "";
for (int i = 0; i < n; ++i)
{
if (i & 1) s1 += s[i];
else s2 += s[i];
}
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
int j = 0, k = 0;
for (int i = 0; i < n; ++i)
{
if (i & 1) cout << s1[j++];
else cout << s2[k++];
}
cout << endl;
}
else
{
sort(s.begin(), s.end());
cout << s << endl;
}
}
return 0;
}
写在最后
这场比赛只做出 A ,果然掉大分咯……其实 B 题当时有猜过 k 为偶数时可能可以直接排序,可能当时累了困了,也没去写一下试一下,说不定碰几次就对了呢……
这类题,没有涉及什么复杂算法,也不需要什么思维,也许只需要在纸上多去模拟、敢于敲代码尝试。有趣的一点是,代码实现的思路不是直接来自于题目(题目会给出很多无用的干扰信息,需要提取有用信息),而是基于手算归纳、猜想得到的推论。也许这个推论背后是严谨的数学证明,但能够归纳、猜想出来,就足够了!