Educational Codeforces Round 20 E. Roma and Poker

1|0差分约束


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

当前位是W,则有

{dis[i]dis[i1]1dis[i1]dis[i]1

当前位是L,则有

{dis[i]dis[i1]1dis[i1]dis[i]1

当前位是D,则有

{dis[i]dis[i1]0dis[i1]dis[i]0

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

{dis[i]dis[0]k1dis[i]dis[i]k1

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

{dis[0]dis[n]kdis[n]dis[0]k{dis[0]dis[n]kdis[n]dis[0]k

考虑除了绝对值等于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; }

2|0DP


W表示1L表示1D表示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; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18521047.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示