Binary String To Subsequences—CF1399D
参考文章
思路
我们先来看看如何将给定字符串划分为最小数量的子序列:
我们顺序遍历字符串
s
s
s 中的
s
i
s_i
si 的时候,需要计算可以放入哪个字符串中(已经由
s
s
s 的子序列生成的字符串)中。这一点无疑很简单,只要某一个字符串结尾字符与
s
i
s_i
si 不同,就可以把
s
i
s_i
si 接到这个字符串的后边。如果所有字符串的结尾字符都与
s
i
s_i
si 相同,那么只要再新开一个字符串,
s
i
s_i
si 第一个字符串。
怎么用代码实现上边的过程呢?
我们在判断
s
i
s_i
si 能不能接在一个字符串的后边的时候,只与这个字符串的末尾字符有关,那么我们就可以这样记录所有字符串:
只记录所有字符串的末尾字符和这个字符串的编号。
因为末尾字符只有 0
和 1
两种,所以我们使用两个数组,分别存储以 0
结尾的字符串的编号和以 1
结尾的字符串的编号。这里为了方便,使用动态数组 vevtor<int>
实现。
C o d e Code Code
#include <bits/stdc++.h>
#define int long long
#define sz(a) ((int)a.size())
#define all(a) a.begin(), a.end()
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;
int n;
void solve() {
cin >> n;
string s; cin >> s; s = " " + s;
int num = 0;
vector <int> v[2]; // 分别表示所有以0、1结尾的字符串的编号
vector<int> ans;
for (int i = 1; i <= n; i ++) {
int x = s[i] - '0';
if (not v[1 - x].empty()) { // 能直接接在不同的字符后边
ans.push_back(v[1 - x].back());
v[x].push_back(v[1 - x].back());
v[1 - x].pop_back();
} else { // 新建一个存储s的子序列的字符串
num ++;
v[x].push_back(num);
ans.push_back(num);
}
}
cout << num << "\n";
for (auto p : ans) {
cout << p << " ";
}
cout << "\n";
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T; cin.get();
while (T --) solve();
return 0;
}