codeforces-#661-D

codeforces-#661-D

八月 06, 2020

D. Binary String To Subsequences

题意

给出一个01串要求取出尽量少的子序列使得每个子序列都形如01010…或1010…

输出最少分出几个子序列,并输出原来每个字符属于哪个子序列

题解

单纯的实现模拟

具体的用两个栈zero,one存 以0 or 1结尾的子序列最后一个字符的原下标

每次遇到一个1 先看栈zero里面有没有以0为结尾的子序列有就取出一个以0为结尾的子序列 更新最后一个字符的

下标并塞入以1为结尾的栈one中 若没有以0为结尾的子序列那么就新开一个子序列以当前的1为结尾压入栈one中

同理遇到一个0也如此操作 最后最少需要分割为zero.size()+one.size()个子序列

每个子序列都形如01010…或1010…

对于每个字符属于哪个子序列 此处设置了一个belong数组

譬如当前拿到一个1 存在以0为结尾的子序列( 它在原串的下标为zero.top() )

那么belong[i]=zero.top() 若不存在以0为结尾的那么

就新开一个以1为结尾的子序列belong[i]=i压入栈one中 最后用belong数组倒着回溯即可分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)
const ll Max=2e5+5;
const double PI=acos(-1);
int belong[Max],ans[Max];
bool vis[Max];
/*
*/
int main() {
Turnoff;
int t;cin>>t;
while(t--){
int n;cin>>n;
string s;cin>>s;
stack<int>zero,one;int temp;
for(int i=0;i<n;i++){
vis[i]=0;
if(s[i]=='1'){
if(zero.empty())one.push(i),belong[i]=i;
else {
belong[i]=zero.top();
zero.pop();one.push(i);
}
}
else{
if(one.empty())zero.push(i),belong[i]=i;
else{
belong[i]=one.top();
one.pop();zero.push(i);
}
}
}
int cnt=0;
cout<<one.size()+zero.size()<<endl;
for(int i=n-1;i>=0;i--){
if(vis[i])continue;
int temp=i;
while(belong[temp]!=temp)ans[temp]=cnt,temp=belong[temp],vis[temp]=1;
ans[temp]=cnt;cnt++;vis[temp]=1;
}
for(int i=0;i<n;i++)cout<<ans[i]+1<<" ";
cout<<endl;
}
}

或者发现每次取得的字符1 or 0 若要重新开一个子序列它都属于 第zero.size()+one.size()个子序列

否则他就接入 zero.top() or one.top() 后 压入栈的信息为以0 or 1 为结尾的子序列是第几组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <bits/stdc++.h>

using namespace std;

int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif

int t;
cin >> t;
while (t--) {
int n;
string s;
cin >> n >> s;
vector<int> ans(n);
vector<int> pos0, pos1;
for (int i = 0; i < n; ++i) {
int newpos = pos0.size() + pos1.size();
if (s[i] == '0') {
if (pos1.empty()) {
pos0.push_back(newpos);
} else {
newpos = pos1.back();
pos1.pop_back();
pos0.push_back(newpos);
}
} else {
if (pos0.empty()) {
pos1.push_back(newpos);
} else {
newpos = pos0.back();
pos0.pop_back();
pos1.push_back(newpos);
}
}
ans[i] = newpos;
}
cout << pos0.size() + pos1.size() << endl;
for (auto it : ans) cout << it + 1 << " ";
cout << endl;
}

return 0;
}