题目链接:http://codeforces.com/contest/1399/problem/D
题目描述:
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⋅\\(10^4\\)) — the number of test cases. Then t test cases follow.
The first line of the test case contains one integer n (1≤n≤2⋅ \\(10^5\\)) — 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⋅ \\(10^5\\) (∑n≤2⋅\\(10^5\\)).
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 \\(a_1\\),\\(a_2\\),…,\\(a_n\\) (1≤\\(a_i\\)≤k), where \\(a_i\\) is the number of subsequence the i-th character of s belongs to.
If there are several answers, you can print any.
最开始的朴素做法(这种做法会TLE):
用一个数组c来存储每个子序列最后的数字,在遍历数组a的同时使\\(a_i\\)遍历数组c,使其接上满足题意的子序列。如果没有找到,\\(a_i\\)单独作为一个子序列。用\\(b_i\\)来记录\\(a_i\\)是属于第几个子序列的,因为是保序的,只需令\\(b_i\\)=j+1就行了。
#include<iostream>#include<vector>using namespace std;int main(){ios::sync_with_stdio(false);cin.tie(0);int t;cin>>t;while(t--){int n;char x;cin>>n;vector<int> a(n+5),b(n+5),c;for(int i=1;i<=n;i++){cin>>x;a[i]=x-\'0\';}c.push_back(a[1]);b[1]=1;for(int i=2;i<=n;i++){int len=c.size();bool flag=true;for(int j=0;j<len;j++){if(a[i]+c[j]==1){c[j]=a[i];b[i]=j+1;flag=false;}if(flag==false)break;}if(flag==true){c.push_back(a[i]);b[i]=len+1;}}cout<<c.size()<<endl;//cout<<\"n==\"<<n<<endl;for(int i=1;i<=n;i++)cout<<b[i]<<\" \";cout<<endl;c.clear();//cout<<\"c.size()==\"<<c.size()<<endl;}return 0;}
正确做法:上面的朴素做法会TLE的根本原因在于对于每一个\\(a_i\\)都要遍历一遍数组c,这样时间复杂度就上去了,而实际上我们只需要对每个\\(a_i\\)判断当前已经存在的子序列中是否有以1结尾的子序列或以0结尾的子序列即可。而不需要每次遍历。因此我们用两个数组分别来存取以0或1结尾的子序列就可以了。这时为了确定\\(b_i\\)的值,我们需要对两个数组中所存储的值进行修改,应该存储的是每个子序列的编号,而不再是0或1了。
#include<iostream>#include<vector>#include<string>using namespace std;string s;int main(){ios::sync_with_stdio(false);cin.tie(0);int t;cin >> t;while (t--){int n;cin >> n >> s;vector<int> b(n + 5), c0, c1;for (int i = 0;i < n;i++){int newpos;if (s[i] == \'0\'){newpos = c0.size() + c1.size();if (c1.empty()){c0.push_back(newpos);}else{newpos = c1.back();c1.pop_back();c0.push_back(newpos);}}else{newpos = c0.size() + c1.size();if (c0.empty()){c1.push_back(newpos);}else{newpos = c0.back();c0.pop_back();c1.push_back(newpos);}}b[i] = newpos + 1;}cout << c0.size() + c1.size() << endl;for (int i = 0;i < n;i++)cout << b[i] << \" \";cout << endl;}return 0;}