AtCoder Beginner Contest 126

AtCoder Beginner Contest 126

https://atcoder.jp/contests/abc126

A - Changing a Character

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n, k;
    string s;
    cin >> n >> k >> s;
    s[k-1] = (char)(s[k-1] - 'A' + 'a');
    cout << s;
}

B - YYMM or MMYY

#include <bits/stdc++.h>

using namespace std;
set<string> month = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};

int main () {
    string s;
    cin >> s;
    bool ok1 = false, ok2 = false;
    string s1 = s.substr (0, 2), s2 = s.substr (2, 2);
    if (month.count (s1))   ok1 = true;
    if (month.count (s2))   ok2 = true;
    if (ok1 && ok2)     cout << "AMBIGUOUS";
    else if (ok1)       cout << "MMYY";
    else if (ok2)       cout << "YYMM";
    else                cout << "NA";
}

C - Dice and Coin

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n, k;
    cin >> n >> k;
    double ans = max (0.0, 1.0 * (n - k + 1) / n);
    //cout << ans << endl;
    for (int i = 1; i < min (k, n + 1); i++) {
        double dx = 1.0 / n;
        for (int j = i; j < k; j *= 2)  dx *= 0.5;
        //cout << dx << ' ';
        ans += dx;
    }
    cout << fixed << setprecision (10) << ans;
}

D - Even Relation

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5, M = N * 2;
int h[N], e[M], ne[M], w[M], idx, n, ans[N];

void add (int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

void dfs (int u, int fa) {
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (j == fa)    continue;
        if (w[i] & 1)   ans[j] = !ans[u];
        else    ans[j] = ans[u];
        dfs (j, u);
    }
}

int main () {
    memset (h, -1, sizeof h);
    cin >> n;
    for (int i = 1; i < n; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        add (a, b, c), add (b, a, c);
    }
    dfs (1, -1);
    for (int i = 1; i <= n; i++)    cout << ans[i] << endl;
}
//嗯搜, 暴力改

E - 1 or 2

由于元素总共只有1,2这两种,所以确定一个就关系就能互推,直接用冰茶几维护有多少个集合即可。

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int fa[N], n, m, ans;

int find (int x) {
    if (x != fa[x])     fa[x] = find (fa[x]);
    return fa[x];
}

int main () {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)    fa[i] = i;
    while (m --) {
        int a, b, c;
        cin >> a >> b >> c;
        a = find (a), b = find (b);
        if (a != b)     fa[a] = b;
    }
    for (int i = 1; i <= n; i++) {
        if (fa[i] == i) ans ++;
    }
    cout << ans;
}

F - XOR Matching

题意

构造一个长度为 \(2^{m+1}\) 的序列,满足 \([0,2^m-1]\) 范围内的每一个数都恰好出现两次且任意两个相等的数之间的异或和 \(=k\)

分析

主要是利用了异或的这两条性质:

\[a\bigotimes 0 = a\\ a\bigotimes a = 0 \]

可以这样构造,两个相同的数中间除了 \(k\) 之外的其他数字只出现偶数次。考虑对称构造,把一个 \(k\) 放在最中间,其余数字左右对称构造。

至于剩下的一个 \(k\) 怎么办?首先要 \(get\) 一个小结论:\(0\)\(2^m-1\) 的异或和为 \(0\) (\(m\neq 1\)) ,粗糙的证明如下:
\(m=0\) 时,\(0\bigotimes 0=0\)\(m>0\) 时,相邻四个数字一组,作异或和,发现除了最低两位以外,其余位上的数字皆相等,而末尾两位分别为 \(00,01,10,11\),异或起来也是0,得证。

所以可以直接把 \(k\) 丢在开头或者结尾。构造如下:
\(0,1,...,k-1,k+1,...,2^m-1,k,\)
\(2^m-1,2^m-2,...,k+1,k-1,...,1,0,k\)

还没完,注意特判:

\(k\geq2^m\),则无法构造,因为最后 \(k\) 一定会被剩下,没法够造出异或和为 \(0\) 的情况。
\(m=1\) 时,样例已给出(无解 + 额外构造)

#include <bits/stdc++.h>

using namespace std;

signed main () {
    int m, k;
    cin >> m >> k;

    if (k >= (1ll << m))    cout << -1; //凑不成两个
    else if (m == 1) {
        if (k)  cout << -1;
        else    cout << "0 0 1 1";
    }
    else {
        for (int i = 0; i < (1ll << m); i++) {
            if (i != k)     cout << i << ' ';
        }
        cout << k << ' ';
        for (int i = (1ll << m) - 1; i >= 0; i--) {
            if (i != k)     cout << i << ' ';
        }
        cout << k << endl;
    }
}

//小结论: 0到2^m-1的异或和为0 (证: 相邻四个一组)
posted @ 2023-01-26 10:27  Sakana~  阅读(38)  评论(0编辑  收藏  举报