构造 / 贪心 - Binary String To Subsequences - CF 1399D

构造 / 贪心 - Binary String To Subsequences - CF 1399D

题意:

给定一个长度为 n 的 01 串,把它分成尽量少的子串,使得每一个子串不出现连续的 0 或 1。

求最少能够分成几组子串,并对于每一个字符,输出它们属于哪一组。

输出任意一组可行解。

Input

The first line of the input contains one integer t ( 1 ≤ t ≤ 2 ⋅ 1 0 4 1≤t≤2⋅10^4 1t2104) — the number of test cases. Then t test cases follow.

The first line of the test case contains one integer n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1≤n≤2⋅10^5 1n2105) — the length of s. The second line of the test case contains n characters ‘0’ and ‘1’ — the string s.

It is guaranteed that the sum of n does not exceed 2⋅105 ( ∑ n ≤ 2 ⋅ 1 0 5 ∑n≤2⋅10^5 n2105).

Output

For each test case, print the answer: in the first line print one integer k ( 1 ≤ k ≤ n 1≤k≤n 1kn) — the minimum number of subsequences you can divide the string s to. In the second line print n integers a1,a2,…,an ( 1 ≤ a i ≤ k 1≤a_i≤k 1aik), where ai is the number of subsequence the i-th character of s belongs to.

If there are several answers, you can print any.

Example
input

4
4
0011
6
111111
5
10101
8
01010000

output

2
1 2 2 1 
6
1 2 3 4 5 6 
1
1 1 1 1 1 
4
1 1 1 1 1 2 3 4 

分析:

维护两个数组: g 0 g_0 g0 g 1 g_1 g1

分别存储以 0 / 1 结尾的子串的组号。

然后我们遍历字符串,

  • 若遇到字符 0,则我们在以 1 结尾的子串中任选一个,把 0 加到这个子串后面即可。此时,原本以 0 结尾的子串就变成了以 1 结尾的子串。如果不存在以 1 结尾的子串,则我们需要创建一个新的以 0 结尾的子串。
  • 若遇到字符 1,同理。
  • 每一个字符处理完后,在数组 a 中记录下该字符所在的组号即可。

代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>

using namespace std;

const int N = 200010;

int t, n;
char s[N];

int main()
{
	scanf("%d", &t);
	while(t --)
	{
		scanf("%d", &n);
		scanf("%s", s);
		vector<int> g0, g1;
		vector<int> a(n);
		for(int i = 0; i < n; i ++)
		{
			int g_idx = g0.size() + g1.size() + 1;
			if(s[i] == '0')
			{
				if(g1.empty()) g0.push_back(g_idx);	// new group
				else
				{
					g_idx = g1.back();	// 取出以 1 结尾的组号 
					g1.pop_back();		// 该组现在以 0 结尾 
					g0.push_back(g_idx);
				}
			}
			else
			{
				if(g0.empty()) g1.push_back(g_idx);
				else
				{
					g_idx = g0.back();
					g0.pop_back();
					g1.push_back(g_idx); 
				}
			}
			a[i] = g_idx;
		}
		
		printf("%d\n", g0.size() + g1.size());
		for(int i = 0; i < n; i ++) printf("%d ", a[i]);
		puts("");
	}

	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值