String Coloring (easy version)

题目连接: String Coloring (easy version)

题目:

This is an easy version of the problem. The actual problems are different, but the easy version is almost a subtask of the hard version. Note that the constraints and the output format are different.

You are given a string s consisting of n lowercase Latin letters.

You have to color all its characters one of the two colors (each character to exactly one color, the same letters can be colored the same or different colors, i.e. you can choose exactly one color for each index in s).

After coloring, you can swap any two neighboring characters of the string that are colored different colors. You can perform such an operation arbitrary (possibly, zero) number of times.

The goal is to make the string sorted, i.e. all characters should be in alphabetical order.

Your task is to say if it is possible to color the given string so that after coloring it can become sorted by some sequence of swaps. Note that you have to restore only coloring, not the sequence of swaps.

Input
The first line of the input contains one integer n (1≤n≤200) — the length of s.
The second line of the input contains the string s consisting of exactly n lowercase Latin letters.

Output
If it is impossible to color the given string so that after coloring it can become sorted by some sequence of swaps, print “NO” (without quotes) in the first line.
Otherwise, print “YES” in the first line and any correct coloring in the second line (the coloring is the string consisting of n characters, the i-th character should be ‘0’ if the i-th character is colored the first color and ‘1’ otherwise).

Examples
Input

9
abacbecfd
Output
YES
001010101

Input
8
aaabbcbb
Output
YES
01011011

Input
7
abcdedc
Output
NO

Input
5
abcde
Output
YES
00000

大致题意就是, 给你一个字符串, 让你给里面的每一个字符上色0或1, 不同颜色的相邻字符之间可以进行交换, 问你最后能不能把这个字符串按字母表排序. 能的话打印YES和涂色顺序, 否则打印NO

解题思路:

思路一: 暴力法(复杂度O(n2))

这个题由于数据量比较小, n最大只有200, 所以可以考虑超级超级暴力的方法直接做: 判断当前第i个字符之前有多少个比他大的, 如果有比他大的, 那么他需要涂相反色, 如果出现两个不同色且都比第i个字符大的字符, 则无解.

思路二: 拆分子串法(复杂度O(n))

这个算是从学长那里学习来的, 由于只能涂两种颜色, 所以我们可以考虑这个字符串能否拆分成两个非降序子串来解决这个问题.

已知如果某字符串是可以按题意排序成字母表顺序的, 那么他拆分出的两个非降序子串各自内部一定是无需交换顺序的, 则只需要考虑子串1与子串2之间交换顺序, 如果子串1的某个i位置字符大于排在子串2某个j位置字符, 则需要交换, 交换后我们可以保证原串在k位置(即i+j-1位置)都是排序好的, 那么只需要从k+1位置开始考虑后续排序.

此时情况分为两种:

  1. k+2位置为子串1的字符, 则与k+1位置同色, 符合非降序要求, 无需交换, 此时可以保证k+1位置都是排序好的(因为k+2可能与k+3交换, 所以k+2无法保证).
  2. k+2位置为子串2的字符, 则一定需要与k+1位置进行交换(否则该位置的字符应该放在子串1中), 且一定可以交换, 所以我们仍然可以保证在k+1位置之前都是排序好的.

无论那种情况, 我们都可以保证将原串的有序字符位置++, 因此我们只需要循环这两种情况, 则一定可以让原串按字母表有序.

综上所述, 我们可以保证如果这个串如果可以分成2个非降序子串, 则有解, 且我们不妨假设子串1涂成0, 子串2涂成1.(复杂度O(n2))

AC代码:

思路一AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool res[1000000]; //存储结果, 不妨默认初始都涂成0
int main(void)
{
	string s; int n; cin >> n >> s;
	
	for (int i = 1; i < n; i++) {
		bool flag = 0; //默认当前字符没有进行过交换
		for (int j = 0; j < i; j++) {
			if (s[j] > s[i]) { //需要交换
				if (res[i] == res[j]) {
					if (flag) { cout << "NO" << endl; return 0; }
					res[i] = res[j] ^ 1; //需要与res[j]的涂色相反
					flag = 1;
				}
			}
		}
	}
	
	cout << "YES" << endl;
	for (int i = 0; i < n; i++) printf("%d", res[i]);
	printf("\n");
	return 0;
}
思路二AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool res[1000000]; //存储结果, 不妨默认初始都涂成0
char s1, s2; //分别假设两个子串1和2, 因为需要按照非降序排序, 所以只需要记录最后一个字符即可.
int main(void)
{
	string s; int n; cin >> n >> s;
	
	for (int i = 0; i < n; i++) {
		if (s[i] >= s1) s1 = s[i]; //大于等于s1, 符合s1非降序, 放在s1里
		else if(s[i] >= s2) s2 = s[i], res[i] = 1; //s1放不了了 看看能不能存在s2里.
		else { cout << "NO" << endl; return 0; } //都存不下, 不能分解成2个非降序子串, 无解.
	}

	cout << "YES" << endl;
	for (int i = 0; i < n; i++) printf("%d", res[i]);
	printf("\n");
	return 0;
}

没啥可说的…ENDEND

END

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逍遥Fau

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

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

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

打赏作者

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

抵扣说明:

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

余额充值