ACWING\3777. 砖块

本文介绍如何在最多3n次操作下,通过巧妙策略将排成一排的黑白砖块颜色统一。特殊情况下如B和W数量奇偶性决定解法,常规情况下涉及转移和颜色翻转操作。算法演示了如何将W移动至右端并调整,适用于B/W数量之一为偶数的情况。
摘要由CSDN通过智能技术生成

n 个砖块排成一排,从左到右编号依次为 1∼n。

每个砖块要么是黑色的,要么是白色的。

现在你可以进行以下操作若干次(可以是 0 次):

选择两个相邻的砖块,反转它们的颜色。(黑变白,白变黑)

你的目标是通过不超过 3n 次操作,将所有砖块的颜色变得一致。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含一个整数 n。

第二行包含一个长度为 n 的字符串 s。其中的每个字符都是 WB,如果第 i 个字符是 W,则表示第 i 号砖块是白色的,如果第 i 个字符是 B,则表示第 i 个砖块是黑色的。

输出格式

每组数据,如果无解则输出一行 −1。

否则,首先输出一行 k,表示需要的操作次数。

如果 k>0,则还需再输出一行 kk 个整数,p1,p2,…,pk。其中 pi 表示第 i 次操作,选中的砖块为 pi 和 pi+1号砖块。

如果方案不唯一,则输出任意合理方案即可。

数据范围

1≤T≤10,
2≤n≤200。

输入样例:

4
8
BWWWWWWB
4
BWBB
5
WWWWW
3
BWB

输出样例:

3
6 2 4
-1
0
2
2 1

题解

特殊情况:

  • 当B和w都为奇数,则一定无法翻转出来,最终一定会得到最后一个相邻的为WB,翻转为BW循环下去无法结局
  • 当B或者W的数量为0时,则0次就可以成功。
  • 正常情况可解即B、W有一个为偶数,解法如下:
    1. 首先将w都转移到最右端
    2. 如果遇到当前和下一个都是w,那就变成b
    3. 若当前是w,下一个是b,则翻转w移动到下一个
    4. 若当前是b,不动
    5. 所有w都到最右端后,如果b是偶数,则全部翻转b,否则全部翻转w
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>

using namespace std;

int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		string s;
		cin>>s;
		int b_cnt = 0, w_bnt = 0;
		for(int i =0;i<n;i++){
			if(s[i] == 'W') w_bnt++;
			else b_cnt++;
		}
		if(w_bnt%2 and b_cnt%2) cout<<-1<<endl;
		else if(w_bnt == 0 or b_cnt == 0) cout<<0<<endl;
		else{
			vector<int> ans;
			// 首先将w都转移到最右端
			// 如果遇到当前和下一个都是w,那就变成b
			// 若当前是w,下一个是b,则翻转w移动到下一个
			// 若当前是b,不动
			for(int i = 0;i<n-1;i++){
				if(s[i] == 'W' and s[i+1] == 'B'){
					ans.push_back(i);
					s[i] = 'B';
					s[i+1] = 'W';
				}else if(s[i] == 'W' and s[i+1] == 'W'){
					ans.push_back(i);
					s[i] = 'B';
					s[i+1] = 'B';
				}
			}
			if(w_bnt%2 == 0){
				// w -> b
				for(int i = 0;i<n-1;i++){
					if(s[i] == 'W' and s[i+1] == 'W'){
						ans.push_back(i);
						s[i] = 'B';
						s[i+1] = 'B';
					}
				}
			}else{
				// b -> w
				for(int i = 0;i<n-1;i++){
					if(s[i] == 'B' and s[i+1] == 'B'){
						ans.push_back(i);
						s[i] = 'W';
						s[i+1] = 'W';
					}
				}
			}
			printf("%d\n",ans.size());
			for(int i = 0;i<ans.size();i++) cout<<ans[i]+1<<" ";
			printf("\n");
		}
	}
		
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlwaysDayOne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值