AtCoder Beginner Contest 338题解

234 阅读3分钟

AtCoder Beginner Contest 338

1.A

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

signed main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    string s;
    cin >> s;
    int n = s.size();
    for (int i = 0; i < n; i++) {
        if (i == 0 && s[i] >= 'a' && s[i] <= 'z') {
            cout << "No" << '\n';
            return 0;
        }
        if (i != 0 && s[i] >= 'A' && s[i] <= 'Z') {
            cout << "No" << '\n';
            return 0;
        }
    }
    cout << "Yes" << '\n';
    return 0;
}

2.B

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

signed main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);

    string s;
    cin >> s;
    int n = s.size();
    vector<int> mx(26, 0);
    int maxx = 0;
    for (int i = 0; i < n; i++) {
        mx[s[i] - 'a']++;
        maxx = max(maxx, mx[s[i] - 'a']);
    }
    for (int i = 0; i < 26; i++) {
        if (mx[i] == maxx) {
            char x = i + 'a';
            cout << x << '\n';
            return 0;
        }
    }
    return 0;
}

3.C

因为N的大小只有10,所以直接考虑枚举一个人dish的数量就行。

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

const int N = 1e6 + 10;
int n;
int q[N], a[N], b[N];
signed main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;

    for (int i = 1; i <= n; i++) {
        cin >> q[i];
    }
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        cin >> b[i];
    }

    int mx = 1 << 30;
    for (int i = 1; i <= n; i++) {
        if (a[i] == 0)
            continue;
        else {
            mx = min(mx, q[i] / a[i]);
        }
    }
    int ans = 0;
    for (int i = 0; i <= mx; i++) {
        int res = 1 << 30;
        for (int j = 1; j <= n; j++) {
            if (b[j] == 0)
                continue;
            res = min(res, (q[j] - a[j] * i) / b[j]);
        }
        res += i;
        ans = max(ans, res);
    }
    cout << ans << '\n';
    return 0;
}

4.D

参考官方题解。

首先我们考虑a -> b是不是有顺时针和逆时针两种方式。考虑顺时针走过的桥为S,逆时针走过的桥为T。

再考虑删除每条边之后的权重。如果删除S,那么权重为T。反之一样。

最后考虑每条边被删除的权重,取一个最小值即可。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    int n, m;
    cin >> n >> m;
    vector<int> x(m);
    for (int &i : x) {
        cin >> i;
        --i;
    }
    vector<ll> v(n + 1);
    auto dist = [&](int from, int to) {
        if (from <= to)
            return to - from;
        else
            return to + n - from;
    };
    auto add = [&](int from, int to, int num) {
        if (from <= to) {
            v[from] += num;
            v[to] -= num;
        } else {
            v[from] += num;
            v[n] -= num;
            v[0] += num;
            v[to] -= num;
        }
    };  
    for (int i = 0; i < m - 1; i++) {
        add(x[i], x[i + 1], dist(x[i + 1], x[i]));
        add(x[i + 1], x[i], dist(x[i], x[i + 1]));
    }
    ll ans = 1LL << 60;
    for (int i = 0; i < n; i++) {
        v[i + 1] += v[i];
        ans = min(ans, v[i]);
    }
    cout << ans << endl;
}

5.E

考虑两条弦有交点,必然是BiB_i出现在另外一条弧的AiBiA_i B_i之间。

我们考虑将A作为左括号,B作为右括号。自己只能和自己匹配。这不就是一个括号匹配问题吗?

如果发生了AiA_iBjB_j的匹配就证明了发生了交叉。

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);

    int n;
    cin >> n;
    vector<pair<int, int>> a(2 * n);
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        x--, y--;
        if (x > y)
            swap(x, y);
        a[x] = {0, i};
        a[y] = {1, i};
    }
    stack<int> s;
    for (int i = 0; i < 2 * n; i++) {
        if (a[i].first == 0) {
            s.push(a[i].second);
        } else {
            if (s.top() != a[i].second) {
                cout << "Yes" << '\n';
                return 0;
            }
            s.pop();
        }
    }
    cout << "No" << '\n';
    return 0;
}

6.F

N<=20,考虑状压DP。

显然是可以的。dp[s][i]dp[s][i]表示S状态下最后一个点为i,状态转移就是dp[s1<<j][j]=min(dp[s1<<j][j],dp[s][i]+d[i][j])dp[s | 1 << j][j] = min(dp[s | 1 << j][j], dp[s][i] + d[i][j])

d[i][j]d[i][j]求的是i,j之间得最短路,所以还需要一个floyd求最短路。

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

const int inf = 1 << 30;
int main() {
    auto chooseMin = [&](int &a, int b) { a = min(a, b); };

    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> d(n, vector<int>(n, inf));
    for (int i = 0; i < n; i++)
        d[i][i] = 0;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        --u, --v;
        d[u][v] = w;
    }
    /**先floyd算两点之间的最短路*/
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (d[i][k] == inf or d[k][j] == inf)
                    continue;
                chooseMin(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
    /**然后做状压dp*/
    int maxx = 1 << n;
    vector<vector<int>> dp(maxx, vector<int>(n, inf));
    for (int i = 0; i < n; i++)
        dp[1 << i][i] = 0;
    for (int bit = 1; bit < maxx - 1; bit++) {
        for (int i = 0; i < n; i++) {
            if (~bit >> i & 1)
                continue;
            if (dp[bit][i] == inf)
                continue;
            for (int j = 0; j < n; j++) {
                if (bit >> j & 1)
                    continue;
                if (d[i][j] == inf)
                    continue;
                chooseMin(dp[bit | 1 << j][j], dp[bit][i] + d[i][j]);
            }
        }
    }
    int ans = inf;
    for (int i = 0; i < n; i++) {
        chooseMin(ans, dp[maxx - 1][i]);
    }
    if (ans == inf)
        cout << "No" << endl;
    else
        cout << ans << endl;
    return 0;
}