Atcoder ABC383

部署运行你感兴趣的模型镜像

C

BFS。放入所有的H点,bfs在D步内能访问到的点。

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

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

int h, w, d;
string s[1100];
int a[1100][1100];
queue<pii> qu;

int dirs[4][2] = {
    {0, 1}, {1, 0}, {0, -1}, {-1, 0}
};


int main(){
    //freopen("in.txt", "r", stdin);
    cin >> h >> w >> d;
    for (int i = 0; i < h; ++i) {
        cin >> s[i];
    }
    memset(a, 0x3f, sizeof(a));
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if (s[i][j] == 'H') {
                a[i][j] = 0;
                qu.push({ i, j });
            }
        }
    }
    while (qu.size()) {
        auto [r, c] = qu.front();
        int step = a[r][c];
        if (step == d) {
            break;
        }
        qu.pop();
        for (auto [dr, dc] : dirs) {
            int nr = dr + r, nc = dc + c;
            if (nr >= 0 && nr < h && nc >= 0 && nc < w && s[nr][nc] == '.') {
                if (a[nr][nc] > step + 1) {
                    qu.push({ nr, nc });
                    a[nr][nc] = step + 1;
                }
            }
        }
    }
    int ans = 0;
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if (a[i][j] <= d) ans++;
        }
    }
    printf("%d\n", ans);
    return 0;
}

D

简单数论题。
有9个因子,说明该数能写成为a2∗b2a^2*b^2a2b2的形式或者a8a^8a8的形式。这里ab都为质数。
因此我们先做出2000000以内的质数表,然后前者暴力或者求前缀和都可以,后者直接暴力。做的时候小心越界。因此我很不要脸的用了python。

# -*- coding: utf-8 -*-
# @time     : 2023/6/2 13:30
# @file     : atcoder.py
# @software : PyCharm

import bisect
import copy
import sys
from itertools import permutations
from collections import defaultdict, Counter, deque
from functools import lru_cache, cmp_to_key
import heapq
import math
sys.setrecursionlimit(100010)


def main():
    items = sys.version.split()
    fp = open("in.txt") if items[0] == "3.10.6" else sys.stdin
    n = int(fp.readline())
    N = 2000001
    b = [0] * N
    prime = []
    sz = 0
    for i in range(2, N):
        if b[i] == 0:
            prime.append(i)
            sz += 1
        for j in range(sz):
            if i * prime[j] >= N:
                break
            b[i * prime[j]] = 1
            if i % prime[j] == 0:
                break

    ans = 0
    for i in range(sz):
        for j in range(i + 1, sz):
            if (prime[i] ** 2) * (prime[j] ** 2) > n:
                break
            ans += 1

    for i in range(sz):
        t = prime[i] ** 8
        if t > n:
            break
        ans += 1

    print(ans)


if __name__ == "__main__":
    main()

E

这种N的排列求最佳匹配已经没有什么算法复杂度可言,关键是找到一种方法去贪心。
考虑类似kruscal求最小生成树的做法,对边排序,从小到大加入。实际上,当点对在同一颗最小生成子树中时,点对的f值就是最小生成树当前遍历的边w。

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

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;


int n, m, k;
struct Edge {
    ll w;
    int u, v;
} e[200020];

int fa[200020];
int dep[200020];
int cnta[200020], cntb[200020];


int get(int u) {
    return u == fa[u] ? u : fa[u] = get(fa[u]);
}

int merge(int u, int v) {
    int fu = get(u), fv = get(v);
    if (fu == fv) 
        return fu;
    if (dep[fu] < dep[fv]) swap(fu, fv);
    cnta[fu] += cnta[fv];
    cntb[fu] += cntb[fv];
    fa[fv] = fu;
    if (dep[fu] == dep[fv]) dep[fu] ++;
    return fu;
}


int main(){
    //freopen("in.txt", "r", stdin);
    cin >> n >> m >> k;
    for (int i = 0; i < m; ++i) {
        int u, v;
        ll w;
        cin >> u >> v >> w;
        e[i] = { w, u, v };
    }
    for (int i = 0; i < k; ++i) {
        int u;
        cin >> u;
        cnta[u] ++;
    }
    for (int i = 0; i < k; ++i) {
        int u;
        cin >> u;
        cntb[u] ++;
    }
    sort(e, e + m, [&](Edge x, Edge y) {
        return x.w < y.w;
        });
    for (int i = 1; i <= n; ++i) {
        fa[i] = i, dep[i] = 0;
    }
    ll ans = 0;
    for (int i = 0; i < m; ++i) {
        auto [w, u, v] = e[i];
        int f = merge(u, v);
        int mn = min(cnta[f], cntb[f]);
        ll t = w * mn;
        cnta[f] -= mn, cntb[f] -= mn;
        ans += t;
    }
    printf("%lld\n", ans);
    return 0;
}

F

分组背包,将同一个颜色归为一组,然后对每一组开一个背包计算在这一组上面容量为j时能获得的最大分数。
g(i,j)g(i,j)g(i,j)是第i组运行完后容量为j时的最大分数。
当前背包的容量为p,分数为u
f(i,j)=min⁡(g(i−1,j−p)+u+k,f(i,j−p)+u)f(i,j)=\min(g(i-1,j-p) + u + k,f(i,j-p)+u)f(i,j)=min(g(i1,jp)+u+k,f(i,jp)+u)
最后再将f更新到g

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

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

ll f[50001], nx[50001];
const ll INF = 1ll << 60;
int n, x;
ll k;
vector<pii> a[505];


int main(){
    //freopen("in.txt", "r", stdin);
    cin >> n >> x >> k;
    for (int i = 1; i <= n; ++i) {
        int p, u, c;
        cin >> p >> u >> c;
        a[c].push_back({ p, u });
    }
    for (int i = 1; i <= x; ++i) f[i] = -INF;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j <= x; ++j)
            nx[j] = -INF;
        
        for (auto [p, u] : a[i]) {
            for (int j = x; j >= p; --j) {
                ll temp = -INF;
                if (f[j - p] >= 0) {
                    temp = max(temp, f[j - p] + u + k);
                }
                if (nx[j - p] >= 0) {
                    temp = max(temp, nx[j - p] + u);
                }
                nx[j] = max(nx[j], temp);
            }
        }
        for (int j = 0; j <= x; ++j) {
            f[j] = max(f[j], nx[j]);
        }
    }
    ll ans = 0;
    for (int i = 0; i <= x; ++i) {
        ans = max(ans, f[i]);
    }
    printf("%lld\n", ans);
    return 0;
}

G

这一期的G题有点难度,dp使用闵可夫斯基和优化。

您可能感兴趣的与本文相关的镜像

Seed-Coder-8B-Base

Seed-Coder-8B-Base

文本生成
Seed-Coder

Seed-Coder是一个功能强大、透明、参数高效的 8B 级开源代码模型系列,包括基础变体、指导变体和推理变体,由字节团队开源

由于无法直接获取AtCoder ABC比赛的最新题解,可通过AtCoder官方网站(https://atcoder.jp/)查看最新比赛场次及题目,比赛结束后,在社区论坛如AtCoder的Discuss板块、GitHub等地方能找到他人分享的题解。 参考之前不同场次题解示例,例如AtCoder ABC 171 C题,是将一个数N转化为26进制用abc表示,模拟过程需注意细节,其AC代码如下: ```cpp #include<iostream> #include<cstdio> #include <stdio.h> #include<algorithm> #include<cstring> #include<cmath> #include<cstdlib> #include<queue> #include<map> #include<vector> #include <set> #define ll long long using namespace std; char a[5000000]; int main() { ll n; ll c=1; int m=0; cin>>n; while(n>0) { ll k=n%(26); if(k==0) { k=26; a[m++]='z'; } else { a[m++]='a'+k-1; } n=(n-k)/26; } for(int i=m-1;i>=0;i--) { cout<<a[i]; } return 0; } ``` 又如AtCoder ABC183题的AC代码如下: ```cpp #include<iostream> #include<bit/stdc++.h> #include<algorithm> #include<vector> #include<numeric> using namespace std; int main(void) { ios_base::sync_with_stdio(false); int N,W; cin >> N >> W; vector<int64_t> v(300000); for(int i = 0; i < N; i++){ int S, T, P; cin >> S >> T >> P; v[S] += P; v[T] -= P; } partial_sum(v.begin(), v.end(), v.begin()); if(*max_element(v.begin(), v.end()) > W) { cout << "No" << endl; } else { cout << "Yes" << endl; } return 0; } ``` 再如AtCoder ABC 242题解,使用while循环往上跳,每次字符往后移动1或2,开变量记录,时间复杂度为$O(Q\log k)$,代码如下: ```cpp #include <bits/stdc++.h> using namespace std; typedef unsigned long long uLL; typedef long double LD; typedef long long LL; typedef double db; const int N = 100005; int n, Ti; char x[N]; int main() { scanf("%s%d", x + 1, &Ti); n = strlen(x + 1); for (LL a, b, c; Ti--; ) { scanf("%lld%lld", &a, &b); c = 0; while (a && b > 1) { if (!(b & 1)) ++c; ++c; b = b + 1 >> 1, a--; } c += a; printf("%c\n", char((x[b] - 'A' + c) % 3 + 'A')); } } ``` 还有AtCoder ABC237题是签到题,可使用C++的INT_MAX和INT_MIN,若不知这两个常数可自行定义,AC代码如下: ```cpp #include<bits/stdc++.h> using namespace std; typedef long long LL; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); LL n; cin>>n; if (n>=INT_MIN && n<=INT_MAX){ cout<<"Yes\n"; }else{ cout<<"No\n"; } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值