AtCoder Beginner Contest 364 补题记录(A~F)

VP 五十八分钟苏童流体。好耶

A

#define GLIBCXX_DEBUG
#include <iostream>
#include <cstring>
#include <cstdio>
#define int long long
const int N = 500100;
std::string s[N];
signed main() {
    int n, cnt = 1;
    scanf("%lld", &n);
    for (int i = 1; i <= n; ++i)
        std::cin >> s[i];
    for (int i = 2; i < n; ++i) {
        if (s[i] == "sweet" && s[i - 1] == "sweet") {
            printf("No\n");
            return 0;
        }
    }
    puts("Yes");
    return 0;
}

B

直接模拟即可。

#define GLIBCXX_DEBUG
#include <iostream>
#include <cstring>
#include <cstdio>
#define int long long
const int N = 500100;
char s[510][510];
signed main() {
    int n, m;
    scanf("%lld%lld", &n, &m);
    int x, y;
    scanf("%lld%lld", &x, &y);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            std::cin >> s[i][j];
    std::string xx;
    std::cin >> xx;
    for (auto &v : xx) {
        if (v == 'U') {
            if (x > 1 && s[x - 1][y] == '.')
                --x;
        } else if (v == 'D') {
            if (x < n && s[x + 1][y] == '.')
                ++x;
        } else if (v == 'L') {
            if (y > 1 && s[x][y - 1] == '.')
                --y;
        } else {
            if (y < m && s[x][y + 1] == '.')
                ++y;
        }
    }
    std::cout << x << ' ' << y << '\n';
    return 0;
}

C

简单贪心。容易发现甜度和咸度互相独立,因此分类甜度最少多少次,咸度最少多少次即可。排一下序就可以求出答案。

时间复杂度为 \(O(n\log n)\)

#define GLIBCXX_DEBUG
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define int long long
const int N = 500100;
int a[N], b[N];
signed main() {
    int n, x, y;
    std::cin >> n >> x >> y;
    for (int i = 1; i <= n; ++i)
        std::cin >> a[i];
    for (int i = 1; i <= n; ++i)
        std::cin >> b[i];
    std::sort(a + 1, a + n + 1, std::greater<>());
    std::sort(b + 1, b + n + 1, std::greater<>());
    int c1 = 0, c2 = 0, s1 = 0, s2 = 0;
    for (int i = 1; i <= n; ++i) {
        s1 += a[i];
        ++c1;
        if (s1 > x) break;
    }
    for (int i = 1; i <= n; ++i) {
        s2 += b[i];
        ++c2;
        if (s2 > y) break;
    }
    std::cout << std::min(c1, c2) << '\n';
    return 0;
}

D

二分套二分板子。考虑对于每一个询问二分距离,然后两个二分分别二分出左边和右边最多可以选择多少个点,判断选择的点数是否超过了 \(k\) 即可。稍微有一点点细节。时间复杂度为 \(O(n\log^2n)\)。不知道有没有单 \(\log\) 做法。

注:代码已更新
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define int long long
const int N = 500100;
int a[N], b[N];
signed main() {
    int n, q;
    std::cin >> n >> q;
    for (int i = 1; i <= n; ++i)
        std::cin >> a[i];
    std::sort(a + 1, a + n + 1);
    for (int i = 1; i <= q; ++i) {
        int b, k;
        std::cin >> b >> k;
        int l = 0, r = 1e9, best = r + 1;
        while (l <= r) {
            int mid = l + r >> 1, cnt = 0;
            int ll = 1, rr = n, b1 = -1;
            while (ll <= rr) {
                int m = ll + rr >> 1;
                if (a[m] >= b - mid)
                    b1 = m, rr = m - 1;
                else
                    ll = m + 1;
            }
            ll = 1, rr = n;
            int b2 = -1;
            while (ll <= rr) {
                int m = ll + rr >> 1;
                if (a[m] <= b + mid)
                    b2 = m, ll = m + 1;
                else
                    rr = m - 1;
            }
            if (b2 - b1 + 1 >= k && b1 != -1 && b2 != -1)
                best = mid, r = mid - 1;
            else
                l = mid + 1;
        }
        std::cout << best << '\n';
    }
    return 0;
}

E

这不 AT_dp_e。最简单的思路是 \(f_{i,j,k}\) 表示当前选择前 \(i\) 个菜肴,甜度为 \(j\),咸度为 \(k\) 最多可以选择多少个菜肴。但是显然过不去。考虑交换状态。设 \(f_{i,j,k}\) 表示当前选择前 \(i\) 个菜肴,选了 \(j\) 个菜肴,当前甜度为 \(k\) 的最小咸度为多少。式子显然。

时间复杂度为 \(O(n^2\min(X,Y))\)

#define GLIBCXX_DEBUG
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
// #define int long long
const int N = 500100;
int a[N], b[N], f[83][83][10010];
signed main() {
    std::ios_base::sync_with_stdio(0);
    std::cin.tie(0);
    int n, x, y;
    std::cin >> n >> x >> y;
    for (int i = 1; i <= n; ++i)
        std::cin >> a[i] >> b[i];
    memset(f, 0x3f, sizeof f);
    f[0][0][0] = 0;
    // f[i][j][k] 表示当前吃了前 i 个菜肴,选择 j 个菜肴,当前甜度为 k 的最小咸度
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= i; ++j)
            for (int k = a[i]; k <= x; ++k)
                for (int p = 0; p < i; ++p)
                    f[i][j][k] = std::min(f[i][j][k], f[p][j - 1][k - a[i]] + b[i]);
    int res = 0;
    for (int i = 1; i <= n; ++i)
    for (int j = 0; j <= n; ++j)
        for (int k = 0; k <= x; ++k)
            if (f[i][j][k] <= y)
                res = std::max(res, j);
    if (res != n)
        ++res;
    std::cout << res << '\n';
    return 0;
}

F

首先把所有的边离线下来按照代价从小到大排序。

然后对于每一条边 \(l\sim r\),若其前面的所有的边都已经加入最小生成树中,则可以考虑维护任意相邻的两个点 \(i,i+1\) 之间的连通性。每一次操作完毕之后一定贪心的让 \(l\sim r\) 中所有的点都连通,也就是说 \(l\sim r-1\) 之间的边全部删除。

直接暴力枚举显然不可行。因此考虑用一个 set 来维护答案,每一次用 lower_bound 找到其下一次要删除的边并将其刹删除。很明显每一条边最多只会被删除 \(1\) 次。因此时间复杂度为 \(O(n\log n)\) 可以通过。

#define GLIBCXX_DEBUG
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
#define int long long
const int N = 2000100;
struct awa {
    int a, b, c;
} wx[N];
bool operator<(const awa &l, const awa &r) {
    return l.c < r.c;
}
int la[N];
signed main() {
    int n, q;
    scanf("%lld%lld", &n, &q);
    for (int i = 1; i <= q; ++i)
        scanf("%lld%lld%lld", &wx[i].a, &wx[i].b, &wx[i].c);
    std::sort(wx + 1, wx + q + 1);
    std::set<int> se;
    for (int i = 1; i <= n; ++i)
        se.insert(i), la[i] = i;
    int cost = 0;
    for (int i = 1; i <= q; ++i) {
        auto it = se.lower_bound(wx[i].a);
        int pos = la[*it], cnt = 0, tm;
        for (; it != se.end() && wx[i].b >= la[*it]; se.erase(tm))
            tm = *it, ++it, ++cnt;
        se.insert(tm), la[tm] = pos;
        cost += cnt * wx[i].c;
    }
    if (se.size() == 1)
        printf("%lld\n", cost);
    else
        puts("-1");
}
posted @ 2024-07-28 10:59  yhbqwq  阅读(95)  评论(1编辑  收藏  举报