【思维构造】Binary String To Subsequences—CF1399D

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 能不能接在一个字符串的后边的时候,只与这个字符串的末尾字符有关,那么我们就可以这样记录所有字符串:
只记录所有字符串的末尾字符和这个字符串的编号。

因为末尾字符只有 01 两种,所以我们使用两个数组,分别存储以 0 结尾的字符串的编号和以 1 结尾的字符串的编号。这里为了方便,使用动态数组 vevtor 实现。

C o d e Code Code

#include 
#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;
}

你可能感兴趣的:(思维构造,算法,c++)