CF1399D Binary String To Subsequences

原题链接:http://codeforces.com/problemset/problem/1399/D

Binary String To Subsequences

You are given a binary string s consisting of n zeros and ones.

Your task is to divide the given string into the minimum number of subsequences in such a way that each character of the string belongs to exactly one subsequence and each subsequence looks like “010101 …” or “101010 …” (i.e. the subsequence should not contain two adjacent zeros or ones).

Recall that a subsequence is a sequence that can be derived from the given sequence by deleting zero or more elements without changing the order of the remaining elements. For example, subsequences of “1011101” are “0”, “1”, “11111”, “0111”, “101”, “1001”, but not “000”, “101010” and “11100”.

You have to answer t independent test cases.

Input

The first line of the input contains one integer t (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⋅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⋅105).

Output

For each test case, print the answer: in the first line print one integer k (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≤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

题目大意

t t t组询问,每组给出字符串的长度 n n n以及一个长度为 n n n的由 0 0 0 1 1 1组成的二进制字符串。

要求将该二进制字符串分成尽可能少的、相邻字符不相同的子串。输出最少的子串数量以及每个字符所在子串的编号(此处允许存在多解)。

题解

我也不知道这是什么,或许算是一个朴素的贪心 + + +模拟?

显然,对于连续的相同字符,我们不可能将他们划分进同一个子串。

同时,为了使子串的数量最少,我们应该尽可能地把一段连续字符分别接入之前已经有的子串,只有当没有可供接入的子串(即最后一个字符与当前字符不同的子串)时,我们才新建一个以当前字符为结尾,长度为一的新子串。

我们要做的就是模拟上述过程,我们可以用两个桶来分别维护末尾为 0 0 0 1 1 1的子串的编号,接入时将编号从一个桶转移到另一个桶,新建时直接往对应的桶里添加元素。

代码

因为询问有很多组,而我们的数组又因为题目要求得开的比较大,所以重置时不能使用 m e m s e t \mathcal{memset} memset,而应手动清零,否则会 T L E \mathcal{TLE} TLE

(话说这套题的出题人是有多喜欢多组询问啊)

另外退役老咸鱼又重新找回了压行的感觉……

#include
using namespace std;
const int M=2e5+5;
int t,n,tot,loc,num;
int buk[M],en[5][M],ans[M];
bool idx;
char bin[M];
void in(){
     scanf("%d%s",&n,bin);}
void re(){
     for(int i=0;i<=n;++i)buk[i]=ans[i]=en[0][i]=en[1][i]=0;}
void add(int l,int r){
     for(int i=l;i<=r;++i)ans[i]=++num,en[idx][++en[idx][0]]=num;}
void link(int l,int r){
     for(int i=l;i<=r;++i)en[idx][++en[idx][0]]=ans[i]=en[!idx][en[!idx][0]],en[!idx][0]--;}
void ac()
{
     
	idx=bin[0]-48,tot=1;
	for(int i=0;i<n;++i,++buk[tot])if(idx!=bin[i]-48)++tot,idx=bin[i]-48;
	idx=(bin[0]-48);
	loc=1,num=0;
	for(int i=1;i<=tot;loc+=buk[i],idx^=1,++i)
	if(buk[i]>en[!idx][0])add(loc+en[!idx][0],loc+buk[i]-1),link(loc,loc+en[!idx][0]-1);
	else link(loc,loc+buk[i]-1);
	printf("%d\n",num);
	for(int i=1;i<=n;++i)printf("%d ",ans[i]);putchar(10);
}
int main()
{
     
	scanf("%d",&t);
	for(int i=1;i<=t;++i)in(),re(),ac();
} 

你可能感兴趣的:(杂============,贪心,模拟)