AtCoder Beginner Contest 235 题解 A F

本文地址

视频讲解

A - Rotate

枚举; 或者观察发现乘以 \(111\)

#include <bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    int a = (int)s[0] - '0' + s[1] - '0' + s[2] - '0';
    cout << a * 111 << "\n";
}


B - Climbing Takahashi

模拟

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)

const int maxn = 1e6 + 5;

int h[maxn];

int main() {
    int n;
    cin >> n;
    inc(i, 1, n) cin >> h[i];
    inc(i, 1, n) {
        if(h[i] >= h[i + 1]) {
            cout << h[i];
            break;
        }
    }
}


C - The Kth Time Query

学会用 map

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)

int main() {
    int n, q;
    cin >> n >> q;
    map<int, vector<int> > mp;
    inc(i, 1, n) {
        int x;
        cin >> x;
        mp[x].push_back(i);
    }
    inc(i, 1, q) {
        int x, k;
        cin >> x >> k;
        if (mp[x].size() < k)
            cout << "-1\n";
        else
            cout << mp[x][k - 1] << "\n";
    }
}


D - Multiply and Rotate

典型的一维 DP

#include <bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn = 1e6 + 5;

int dp[maxn];

int main() {
    int a, n;
    cin >> a >> n;
    queue<int> que;
    que.push(1);
    dp[1] = 1;
    while (que.size()) {
        int q = que.front();
        que.pop();
        ll p = 1LL * q * a;
        if (p < 1000000) {
            if (!dp[p]) {
                dp[p] = dp[q] + 1;
                que.push(p);
            }
        }
        if (q % 10 && q >= 10) {
            int p = q / 10 + (q % 10) * (int)(pow(10, (int)log10(q)));
            if (!dp[p]) {
                dp[p] = dp[q] + 1;
                que.push(p);
            }
        }
    }
    cout << dp[n] - 1 << "\n";
}


E - MST + 1

Kruskal 算法, 把询问和树边一起排序

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)

const int maxn = 1e6 + 5;

struct edge {
    int u, v, c, f;
    bool operator<(const edge& o) { return c < o.c; }
} e[maxn];

int par[maxn];

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

bool same(int x, int y) {
    return find(x) == find(y);
}

void unite(int x, int y) {
    if (!same(x, y))
        par[find(x)] = find(y);
}

int main() {
    int n, m, q;
    cin >> n >> m >> q;
    inc(i, 0, m - 1) {
        int u, v, c;
        cin >> u >> v >> c;
        e[i] = {u, v, c, 0};
    }
    inc(i, 1, q) {
        int u, v, c;
        cin >> u >> v >> c;
        e[m + i - 1] = {u, v, c, i};
    }
    sort(e, e + m + q);
    inc(i, 1, n) par[i] = i;
    vector<int> res(q + 1);
    inc(i, 0, m + q - 1) {
        if (!e[i].f) {
            unite(e[i].u, e[i].v);
        } else {
            if (!same(e[i].u, e[i].v))
                res[e[i].f] = 1;
        }
    }
    inc(i, 1, q) if (res[i]) cout << "Yes\n";
    else cout << "No\n";
}


F - Variety of Digits

题意: 给定 \(N\leq 10^{10^4}\), \(M\)\(0\leq C_i<10\), 求所有 \(x<N\) 且数位包含所有 \(C_i\)\(x\) 之和, 模 \(998244353\).

比较自然想到状压+数位 DP, 不过有点不好写.

\(dpc[S]:\) 二进制位包含 \(S\) 集合的数字个数

\(dps[S]:\) 二进制位包含 \(S\) 集合的数字之和

数位 DP 里的 limit, 意思是前缀是否与最大值的一致. 我们转移分三类

no-limit 转移到 no-limit, 当前位取 \([0,9]]\)

limit 转移到 no-limit, 当前位取 \([0,a[i]-1]\)

limit 转移到 limit, 其实只更新一个值

注意前导0不计入0的出现, 要额外处理.

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
#define ll long long

const int maxn = 1e6 + 5;
const int mod = 998244353;
const int S = 1 << 10;

int a[maxn];
ll fac[maxn];

int main() {
    string s;
    int m;
    cin >> s >> m;
    int n = s.size();
    inc(i, 1, n) a[i] = s[i - 1] - '0';
    int C = 0;
    inc(i, 1, m) {
        int x;
        cin >> x;
        C |= 1 << x;
    }
    fac[n] = 1;
    for (int i = n - 1; i >= 1; i--)
        fac[i] = fac[i + 1] * 10 % mod;
    vector<ll> dpc(S), dps(S);
    int pre_or = 0;
    ll pre_sum = 0;
    inc(i, 1, n) {
        vector<ll> ndpc(S), ndps(S);
        // positive:
        //   no-limit -> no-limit
        inc(j, 1, S - 1) inc(k, 0, 9) {
            ndpc[j | 1 << k] += dpc[j];
            ndps[j | 1 << k] += dps[j] + k * fac[i] % mod * dpc[j] % mod;
        }
        //   limit -> no-limit
        if (pre_or) {
            inc(j, 0, a[i] - 1) {
                ndpc[pre_or | 1 << j] += 1;
                ndps[pre_or | 1 << j] += pre_sum + j * fac[i] % mod;
            }
        }
        //   limit update
        pre_or |= 1 << a[i];
        pre_sum = (pre_sum + a[i] * fac[i]) % mod;
        // zero:
        if (i == 1) {
            inc(j, 1, a[i] - 1) {
                ndpc[1 << j] += 1;
                ndps[1 << j] += j * fac[i] % mod;
            }
        } else {
            inc(j, 1, 9) {
                ndpc[1 << j] += 1;
                ndps[1 << j] += j * fac[i] % mod;
            }
        }

        for (ll& e : ndpc)
            e %= mod;
        for (ll& e : ndps)
            e %= mod;
        dpc = ndpc, dps = ndps;
    }
    ll ans = 0;
    inc(i, 0, S - 1) if ((i & C) == C) { ans += dps[i]; }
    if ((pre_or & C) == C)
        ans += pre_sum;
    cout << ans % mod << "\n";
}

原文地址:https://www.cnblogs.com/linqi05/p/15814138.html