2021 ICPC 沈阳站 补题
E. Edward Gaming, the Champion
签到题,扫一遍判断就行
F. Encoded Strings I
简单题,先 \(O(n^2)\) 大力预处理出来所有字符串,然后直接 sort
B. Bitwise Exclusive-OR Sequence
题意简述
一个需要填数的序列,给定多个限制,每个限制形如 \(a_u \oplus a_v = a_w\) 表示第 \(u\) 个数与第 \(v\) 个数的异或值要为 \(w\),求这个序列的和最小可以为多少
解题思路
首先可以发现这个题目形式有点像图论模型,于是可以考虑把限制看成边,建一张无向图
但是并没有什么用,还是没法确定出方案来,因为一个点改变,其他数都是会变的
所以考虑固定一个点,比如把 1 号点设为 0 去求方案,利用异或的传递性可以知道这样是有唯一方案的
如何判断合法性?图上,01(黑白),考虑按照边限制进行染色判断,一遍dfs即可,出现矛盾就-1
接下来就可以直接按位贪心了,对每一位进行图染色,优先选取颜色数少的那个加入答案
const int MAXN = 1e5 + 10;
int n, m;
struct Edge {
int v, w;
}; std::vector<Edge> G[MAXN];
int vis1[MAXN]; bool fail;
void dfs1(int u, int res) {
if (fail) return;
vis1[u] = res;
for (auto e : G[u]) {
int v = e.v, w = e.w;
int nr = res ^ w;
if (vis1[v] == -1) dfs1(v, nr);
else if (vis1[v] != -1 && vis1[v] != nr) {
fail = true; return;
}
if (fail) return;
}
}
int col[MAXN][40], color[2];
void dfs2(int u, int bit) {
++color[col[u][bit]];
for (auto e : G[u]) {
int v = e.v, w = e.w;
if (col[v][bit] == -1) {
if ((w >> bit) & 1 == 1) col[v][bit] = col[u][bit] ^ 1;
else col[v][bit] = col[u][bit];
dfs2(v, bit);
}
}
}
int main() {
n = read(); m = read();
memset(vis1, -1, sizeof vis1);
memset(col, -1, sizeof col);
for (int i = 1; i <= m; ++i) {
int u = read(); int v = read(); int w = read();
G[u].push_back({v, w});
G[v].push_back({u, w});
}
for (int i = 1; i <= n; ++i) if (vis1[i] == -1) dfs1(i, 0);
if (fail) {
printf("-1\n"); return 0;
}
long long int ans = 0;
for (int i = 1; i <= n; ++i) {
if (col[i][0] == -1) {
for (int bit = 0; bit <= 30; ++bit) {
color[0] = color[1] = 0;
col[i][bit] = 1;
dfs2(i, bit);
ans += 1ll * (std::min(color[0], color[1])) * (1ll << bit);
}
}
} printf("%lld\n", ans);
return 0;
}
J. Luggage Lock
题意简述
一个四位数,每次操作可以把一段连续的位+1或-1,给定初始状态和末状态,求最少多少次操作
解题报告
也是转图论模型,每个四位数状态看成一个点,有总共20种操作(+1-1各10种)连到下一个四位数,跑一遍 bfs 即可
但是多组询问都跑 bfs 容易 T,于是考虑能不能把这玩意预处理出来
发现 1111->2222 和 0000->1111 本质是一样的,也就是对应位的数字差都相同,方案自然也就相同
所以现在就很明确了,预处理 0000 到所有其他值的操作步数,然后对于每次询问,将给定的两个状态的数字差求出来,利用上面的性质转化成 0000 到状态数字差的距离,直接输出即可
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define DEBUG(x) std::cerr << #x << " = " << x << std::endl;
#define forall(G, i_) for (int i_ = 0, __for_siz__ = (int) G.size(); i_ < __for_siz__; ++i_)
#define ALL(x) (x).begin(), (x).end()
typedef long long int lli;
using std::cin;
using std::cout;
using std::endl;
inline int read() {
int s = 0, x = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); }
while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); }
return s * x;
}
inline int readll() {
long long int s = 0, x = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); }
while (isdigit(ch)) { s = s * 10ll + ch - '0'; ch = getchar(); }
return s * x;
}
std::map<std::string, int> dist;
const std::string ops[] = {
"0001", "0010", "0100", "1000",
"0011", "0110", "1100",
"0111", "1110", "1111"
};
std::string getNext(std::string s, int id, int bt) {
std::string res;
for (int i = 0; i < 4; ++i) {
res += (char) (((s[i] - '0') + (ops[id][i] - '0') * bt + 10) % 10 + '0');
} return res;
}
void Pre() {
std::queue<std::string> q;
q.push("0000"); dist["0000"] = 0;
while (!q.empty()) {
std::string u = q.front(); q.pop();
for (int i = 0; i < 10; ++i) {
std::string nx = getNext(u, i, 1);
if (!dist.count(nx)) {
dist[nx] = dist[u] + 1;
q.push(nx);
}
}
for (int i = 0; i < 10; ++i) {
std::string nx = getNext(u, i, -1);
if (!dist.count(nx)) {
dist[nx] = dist[u] + 1;
q.push(nx);
}
}
}
}
int main() {
std::ios::sync_with_stdio(false);
int T; cin >> T;
Pre();
while (T --> 0) {
std::string a, b;
cin >> a >> b;
std::string x;
for (int i = 0; i < 4; ++i) x += (char) (((a[i] - b[i]) + 10) % 10 + '0');
cout << dist[x] << endl;
}
return 0;
}