acwing3777-砖块题解(南昌理工学院ACM暑假集训队)

本文介绍了一种通过分析砖块颜色变化规律,以O(1)复杂度解决使所有砖块颜色一致的算法问题。文章列举了四种不同情况的处理方式:颜色均为偶数、均为奇数、一个为0、一个为奇数,通过判断和操作实现不超过3n次的翻转。代码示例展示了如何实现这一解决方案。


话不多说直接上题目!!

一、题目

点击下面啦!
砖块

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

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

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

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

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

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

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

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

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

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

如果 k>0,则还需再输出一行 k 个整数,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

注意!答案不唯一,那么我们直接看例子!还有就是两个相邻的字母都改变!今天我们用O(1)复杂度来解决这个简单问题!

二、思路

1.

目标是通过不超过 3n 次操作,将所有砖块的颜色变得一致。
我们先设置两个变量cntb,和cntw分别表示字符串中字母为’B’的个数,和字符串中字母为’W’的个数。
先来看第一个例子,我们可以看出cntb和cntw都为偶数,并且我们可以发现无论把结果变成全为”B“还是”W“都为正确答案!

if (cntb % 2 == 0 && cntw % 2 == 0) {
			for (int i = 1; i < len; i++)
			{
				if (a[i] != a[0]) {
					if (a[i + 1] == 'B')a[i + 1] = 'W';
					else a[i + 1] = 'B';
					q.push(i+1);
				}
			}
			cout << q.size() << endl;
			while (!q.empty()) {
				cout << q.front() << " "; q.pop();
			}
			cout << endl;
			continue;
		}

再看第二个例子,我们看出cntb和cntw都为奇数,我们可以举出例子,当cntb和cntw都为奇数的时候,答案其实是无解的:
eg:BWWW变成BBBW无解,BBBWWW变成BBBBBW也无解,因为最终改变的结果有一个单独的字母,所以我们可以得到字母都为奇数的情况下无解

if (cntw % 2 == 1 && cntb % 2 == 1) {
			cout << -1 << endl; continue;
		}

第三个例子,那就是cntb和cntw有一个为0,也就是本来就是同色,直接输出0即可!

if (cntw == 0 || cntb == 0) {
			cout << 0 << endl; continue;
		}

第四个例子,那就是cntb和cntw有一个为偶数,一个为奇数。由第二个例子可以得出,在第二个例子最后的改变中,再加一个可以改变的字母,结果就能全部变成同色!
eg:BWW变成BBB,BBWWW变成WWWWW
而且不能发现只能改变成字母数为奇数的那个字母!
在这里分两种,一种是cntb为奇数,另一种是cntw为奇数

if (cntw % 2 == 1) {
			for (int i = 0; i < len; i++)
			{
				if (a[i] == 'B') {
					q.push(i+1);
					if (a[i + 1] == 'W')a[i + 1] = 'B';
					else a[i + 1] = 'W';
				}
			}
			cout << q.size() << endl;
			while (!q.empty()) {
				cout << q.front() << " "; q.pop();
			}
			cout << endl;
			continue;
		}
		if (cntb % 2 == 1) {
			for (int i = 0; i < len; i++)
			{
				if (a[i] == 'W') {
					p.push(i+1);
					if (a[i + 1] == 'W')a[i + 1] = 'B';
					else a[i + 1] = 'W';
				}
			}
			cout << p.size() << endl;
			while (!p.empty()) {
				cout << p.front() << " "; p.pop();
			}
			cout << endl;
			continue;
		}

代码

不难发现我们用规律的方式也可以写出这道题,我看了一下其他人用dp做的,可能我dp学的不太行吧,嘻嘻本人蒟蒻!

using namespace std;
int t, n;
int main()
{
	cin >> t;
	while (t--)
	{
		cin >> n;
		string a;
		cin >> a;
		queue<int> q,p;
		int cntw = 0, cntb = 0;
		int len = a.length();
		for (int i = 0; i < len; i++)
		{
			if (a[i] == 'W')cntw++; else cntb++;
		}
		if (cntw % 2 == 1 && cntb % 2 == 1) {
			cout << -1 << endl; continue;
		}
		else if (cntw == 0 || cntb == 0) {
			cout << 0 << endl; continue;
		}
		if (cntw % 2 == 1) {
			for (int i = 0; i < len; i++)
			{
				if (a[i] == 'B') {
					q.push(i+1);
					if (a[i + 1] == 'W')a[i + 1] = 'B';
					else a[i + 1] = 'W';
				}
			}
			cout << q.size() << endl;
			while (!q.empty()) {
				cout << q.front() << " "; q.pop();
			}
			cout << endl;
			continue;
		}
		if (cntb % 2 == 1) {
			for (int i = 0; i < len; i++)
			{
				if (a[i] == 'W') {
					p.push(i+1);
					if (a[i + 1] == 'W')a[i + 1] = 'B';
					else a[i + 1] = 'W';
				}
			}
			cout << p.size() << endl;
			while (!p.empty()) {
				cout << p.front() << " "; p.pop();
			}
			cout << endl;
			continue;
		}
		if (cntb % 2 == 0 && cntw % 2 == 0) {
			for (int i = 1; i < len; i++)
			{
				if (a[i] != a[0]) {
					if (a[i + 1] == 'B')a[i + 1] = 'W';
					else a[i + 1] = 'B';
					q.push(i+1);
				}
			}
			cout << q.size() << endl;
			while (!q.empty()) {
				cout << q.front() << " "; q.pop();
			}
			cout << endl;
			continue;
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值