黑白棋
题目描述
小 Z 迷上了棋类游戏,聪明的他很快就摸清了黑白棋、五子棋和围棋的规则,但今天 Prof. Wang 给了他一项挑战:需将杂乱的棋子按黑白相间的特定序列排列。小 Z 决定通过交换棋子位置的方式将它们排列整齐,对于位置分别为 i , j i,j i,j 的两颗棋子,需要花费 ∣ i − j ∣ k \lvert i-j\rvert^k ∣i−j∣k 的代价完成交换。杂乱无章的棋子让小Z头疼不已,你能帮帮他,找到让代价最小的交换方式吗?
输入格式
第一行包含一个整数 T T T 表示测试数据的种类数.
接下来
2
⋅
y
2 \cdot y
2⋅y 行,对于每组测试数据,第一行为一个整数
k
k
k ,表示代价函数的类型,第二行一个由 B
和 W
组成的长度为
l
l
l 的字符串,分别表示黑色和白色。
输出格式
T T T 行, 每行输出一个整数,表示最小的总代价。如果不存在一种方案使得棋子黑白相间排列,输出 − 1 -1 −1。
样例输入
1
2
BWBWW
样例输出
2
样例解释
交换 1 1 1 位置的黑点和 2 2 2 位置的白棋,以及 3 3 3 位置的黑棋和 4 4 4 位置的白棋,序列变为 WBWBW,代价为 2。可以证明这是代价最小的一种方案。
数据范围
每组测试数据保证 1 ≤ T ≤ 5 1 \le T \le 5 1≤T≤5。
对于 20 % 20 \% 20% 的数据, k = 0 , 1 ≤ l ≤ 10 k=0,1 \le l \le 10 k=0,1≤l≤10。
对于 40 % 40 \% 40% 的数据, k = 0 , 1 ≤ l ≤ 100 k=0,1 \le l \le 100 k=0,1≤l≤100。
对于 70 % 70 \% 70% 的数据, k = 0 , 1 ≤ l ≤ 1000 k=0,1 \le l \le 1000 k=0,1≤l≤1000。
对于 100 % 100 \% 100% 的数据, k = 0 , 1 ≤ l ≤ 1 0 5 k=0,1 \le l \le 10^5 k=0,1≤l≤105。
黑白棋 题解
20 % 20\% 20% 的数据可以爆搜,这里不详细说了,我们重点讲正解。
几个非常显而易见的性质:我们总不能动位置已经正确的棋子;当黑色、白色棋子数量差大于 1 的时候,一定无解。
其实做着做着可以发现这个 k k k 是没有用的,因为对于 i i i 和 j j j 的对调,显然最优的对调方案是相邻的两个黑白棋对调,一眼丁真这肯定是最优的。相邻两个棋子,意味着它们的位置差是 1,即 1 k 1^k 1k 永远等于 1。
那么扩展开来,对于两个不相邻的错误棋子,它们在错误棋子的序列中是连续的,尽管实际位置不同,但总可以通过上述方法调换。
举个例子:若错误的黑色棋子位置是 i i i,离它最近的下一个错误的白色棋子位置是 j j j,那么将它俩移动到正确位置的代价是 ∣ i − j ∣ \lvert i - j \rvert ∣i−j∣。
好的,现在经过一通分析,做法也呼之欲出:从前往后遍历整个棋子序列,如果发现有错误的棋子,就查看我们的“错误棋子队列”:如果队列内有在它前面的、异色的、错误的棋子,就把该棋子取出队列和它进行调换;如果没有,就将该棋子放入队列。
最后,需要注意一点:如果k是0,那么无论两棋子间距离有多大,调换的代价都是 1。
代码:
#include <bits/stdc++.h>
using namespace std;
int t , k;
string s;
int sum0 , sum1;
queue <int> q;
int main() {
// freopen("1.in" , "r" , stdin);
// freopen("1.out" , "w" , stdout);
cin >> t;
while(t --) {
while(!q.empty()) q.pop();
sum0 = sum1 = 0;
int ans = 0;
cin >> k;
cin >> s;
int lens = s.length();
s = " " + s;
for(int i = 1 ; i <= lens ; ++ i) {
if(s[i] == 'W') sum1 ++;
else sum0 ++;
}
if(abs(sum1 - sum0) > 1) {
cout << "-1" << endl;
continue;
}
if(sum0 > sum1) {
for(int i = 1 ; i <= lens ; ++ i) {
if(i % 2 == 0 && s[i] == 'B') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'W') {
q.pop();
if(k == 0) ans ++;
else ans += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
else if(i % 2 == 1 && s[i] == 'W') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'B') {
q.pop();
if(k == 0) ans ++;
else ans += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
}
}
else if(sum0 < sum1) {
for(int i = 1 ; i <= lens ; ++ i) {
if(i % 2 == 0 && s[i] == 'W') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'B') {
q.pop();
if(k == 0) ans ++;
else ans += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
else if(i % 2 == 1 && s[i] == 'B') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'W') {
q.pop();
if(k == 0) ans ++;
else ans += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
}
}
else {
int cnt = 0;
for(int i = 1 ; i <= lens ; ++ i) {
if(i % 2 == 0 && s[i] == 'W') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'B') {
q.pop();
if(k == 0) cnt ++;
else cnt += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
else if(i % 2 == 1 && s[i] == 'B') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'W') {
q.pop();
if(k == 0) cnt ++;
else cnt += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
}
for(int i = 1 ; i <= lens ; ++ i) {
if(i % 2 == 0 && s[i] == 'B') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'W') {
q.pop();
if(k == 0) ans ++;
else ans += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
else if(i % 2 == 1 && s[i] == 'W') {
if(!q.empty()) {
int t = q.front();
if(s[t] == 'B') {
q.pop();
if(k == 0) ans ++;
else ans += abs(i - t);
}
else q.push(i);
}
else q.push(i);
}
}
ans = min(ans , cnt);
}
cout << ans << endl;
}
return 0;
}