CF1747B - BAN BAN
题目
BAN BAN - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路
- 题目要求串联n个"BAN",交换任意两个字母让序列不存在"BAN"子序列的最小交换次数。
- 我们可以很容易想到在B后面不存在A和N或者不存在A、不存在N,时肯定不存在子序列"BAN"。而显然让A或N其中一个字符不在B的后面时交换的次数肯定更少。
- 把每个"BAN"编号从1到n,我们可以让第1个"BAN"的A和第n"BAN"的N交换,第2个"BAN"的A和第n-1"BAN"的N交换,···,第i个"BAN"的A和第n-i+1"BAN"的N交换···
- 当n为偶数时刚好两两一对交换完需要n/2次,当n为奇数时最中间的"BAN"和自己交换需要n/2+1次,所以最小交换次数为n/2向上取整,即(n+1)/2次。
- 我们可以有下面3种交换策略,选其中一种即可:
- 让B后面没有A,i*3-2(第i个B)和(n-i+1)*3-1(第n-i+1个A)交换。
- 让B后面没有N,i*3-2(第i个B)和(n-i+1)*3(第n-i+1个N)交换。
- 让A后面没有N,i*3-1(第i个A)和(n-i+1)*3(第n-i+1个N)交换。
代码
#include <bits/stdc++.h>
using namespace std;
// 记录多少个测试用例
int T;
int main() {
cin >> T;
// T个测试用例
while (T--) {
int n;
// n个"BAN"串联
cin >> n;
// 最少需要交换(n + 1) / 2
cout << (n + 1) / 2 << endl;
// 进行(n + 1) / 2次交换,从第1个"BAN"开始
for (int i = 1; i <= (n + 1) / 2; i++) {
// 让A后面没有N,i*3-1(第i个A)和(n-i+1)*3(第n-i+1个N)交换。
cout << 3 * i - 1 << ' ' << (n - i + 1) * 3 << endl;
}
}
return 0;
}
复杂度分析
- 时间复杂度O(n*T)
- 空间复杂度O(1)