Educational Codeforces Round 20 E. Roma and Poker

差分约束

我们记W表示\(1\)L表示\(-1\)D表示\(0\),然后记前\(i\)位的前缀和是\(dis[i]\)。则我们可以根据题面得到如下约束。

当前位是W,则有

\[\left\{\begin{matrix} dis[i] - dis[i-1] \le 1 \\ dis[i-1] - dis[i] \le -1 \end{matrix}\right. \]

当前位是L,则有

\[\left\{\begin{matrix} dis[i] - dis[i-1] \le -1 \\ dis[i-1] - dis[i] \le 1 \end{matrix}\right. \]

当前位是D,则有

\[\left\{\begin{matrix} dis[i] - dis[i-1] \le 0 \\ dis[i-1] - dis[i] \le 0 \end{matrix}\right. \]

前缀和的绝对值小于\(k\),则有

\[\left\{\begin{matrix} dis[i] - dis[0] \le k-1 \\ dis[i] - dis[i] \le k-1 \end{matrix}\right. \]

所有位置的和的绝对值等于\(k\),则有

\[\left\{\begin{matrix} dis[0] - dis[n] \le -k \\ dis[n] - dis[0] \le k \end{matrix}\right. \or\left\{\begin{matrix} dis[0] - dis[n] \le k \\ dis[n] - dis[0] \le -k \end{matrix}\right. \]

考虑除了绝对值等于\(k\)外的约束都是唯一的,因此我们可以在最后先加入绝对值等于\(k\)的其中一种约束,跑一遍差分约束后,删边,再加入另一种约束,再跑一遍差分约束。如果都没有解,就是无解。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int,int>;

const i64 inf = LLONG_MAX / 2;

i32 main(){
	ios::sync_with_stdio(false), cin.tie(nullptr);
	int n, k;
	cin >> n >> k;

	string s;
	cin >> s;
	s = " " + s;

	vector<vector<pii>> e(n + 1);

	for(int i = 1; i <= n; i ++) {
		if(s[i] == 'W') {
			e[i].emplace_back(i - 1, -1);
			e[i - 1].emplace_back(i , 1);
		} else if(s[i] == 'L') {
			e[i].emplace_back(i - 1, 1);
			e[i - 1].emplace_back(i, -1);
		} else if(s[i] == 'D') {
			e[i].emplace_back(i - 1, 0);
			e[i - 1].emplace_back(i, 0);
		} else {
			e[i].emplace_back(i - 1, 1);
			e[i - 1].emplace_back(i, 1);
		}
	}

	for(int i = 1; i < n; i ++) { 
		e[i].emplace_back(0, k - 1);
		e[0].emplace_back(i, k - 1);
	}

	vi dis;
	auto bellman_ford = [n, &e, &dis]() -> bool {
		vi vis(n + 1, 0), tot(n + 1, 0);
		dis = vi(n + 1, inf);

		dis[0] = 0, vis[0] = 1;
		queue<int> q;
		q.push(0);
		while(not q.empty()) {
			int x = q.front();
			q.pop();
			vis[x] = 0;
			for(auto [y, w] : e[x]) {
				if(dis[y] <= dis[x] + w) continue;
				dis[y] = dis[x] + w;
				if(vis[y]) continue;
				if(++ tot[y] == (n + 1)) return false;
				vis[y] = 1;
				q.push(y);
			}
		}
		return true;
	};


	e[n].emplace_back(0, -k);
	e[0].emplace_back(n, k);
	if(bellman_ford()) {
		for(int i = 1, x; i <= n; i ++) {
			x = dis[i] - dis[i - 1];
			cout << "LDW"[x + 1];
		}
		return 0;
	}

	e[n].pop_back(), e[n].emplace_back(0, k);
	e[0].pop_back(), e[0].emplace_back(n, -k);
	if(bellman_ford()) {
		for(int i = 1, x; i <= n; i ++) {
			x = dis[i] - dis[i - 1];
			cout << "LDW"[x + 1];
		}
		return 0;
	}
	cout << "NO";
	return 0; 
}

DP

W表示\(1\)L表示\(-1\)D表示\(0\)

设状态\(f[i][j]\)表示前\(i\)位和为\(j\)的是否成立。如果是问号的话我们就枚举当前位的状态。转移过程中记录一下前序状态即可。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int,int>;

const i64 inf = LLONG_MAX / 2;

i32 main(){
	ios::sync_with_stdio(false), cin.tie(nullptr);
	int n, k;
	cin >> n >> k;

	string s;
	cin >> s;
	s = " " + s;

	vector<map<int,bool>> f(n + 1);
	vector<map<int,int>> lst(n + 1);

	f[0][0] = true;

	for(int i = 1, K; i <= n; i ++) {
		K = k - (i != n);
		if(s[i] == '?') {
			for(int d = -1; d <= 1; d ++) {
				for(int j = -K; j <= K; j ++)
					if(f[i - 1][j - d]) f[i][j] = true, lst[i][j] = j - d;
			}
		} else {
			int d = 0;
			if(s[i] == 'W') d = 1;
			else if(s[i] == 'L') d = -1;
			for(int j = -K, l; j <= K; j ++) 
				if(f[i - 1][j - d]) f[i][j] = true, lst[i][j] = j - d;
		}
	}

	if(f[n][k]) {
		string res;
		for(int i = n, j = k, l, x; i > 0; i --) {
			l = lst[i][j], x = j - l;
			res += "LDW"[x + 1];
			j = l;
		}
		ranges::reverse(res);
		cout << res;
	}else if(f[n][-k]) {
		string res;
		for(int i = n, j = -k, l, x; i > 0; i --) {

			l = lst[i][j], x = j - l;
			res += "LDW"[x + 1];
			j = l;
		}
		ranges::reverse(res);
		cout << res;
	} else {
		cout << "NO";
	}
	return 0; 
}
posted @ 2024-11-01 18:47  PHarr  阅读(3)  评论(0编辑  收藏  举报