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;
}
posted @ 2023-09-01 11:47  Handwer  阅读(23)  评论(0编辑  收藏  举报