构造 / 贪心 - 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 1≤t≤2⋅104) — 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 1≤n≤2⋅105) — 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 ∑n≤2⋅105).
Output
For each test case, print the answer: in the first line print one integer k ( 1 ≤ k ≤ n 1≤k≤n 1≤k≤n) — 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 1≤ai≤k), 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;
}