AtCoder Beginner Contest 373

AtCoder Beginner Contest 373

题目链接:AtCoder Beginner Contest 373 - AtCoder

A:September

题目链接:September

题目描述:

输入12个字符串,输出这些字符串中满足条件的个数。条件是:第i个字符串应当由小写字母组成,且其长度为i。

解题思路:

遍历每个字符串,判断其长度是否为i,且所有字符是否都是小写字母。如果满足条件,计数加1。

C++代码实现:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

void solved() {
    int ans = 0;
    for (int i = 1; i <= 12; i++) {
        string s;
        cin >> s;
        if(s.length() == i) {
            bool flag = true;
            for (int j = 0; j < i; j++) {
                if(!(s[j] >= 'a' && s[j] <= 'z')) {
                    flag = false;
                    break;
                }
            }
            ans += flag;
        }
    }
    cout << ans << endl;
}

signed main() {
    close;
    solved();
    return 0;
}

B:1D Keyboard

题目链接:1D Keyboard

题目描述:

输入一个由字母 A 到 Z 组成的排列,计算从字母 A 开始依次移动到 Z 的总移动距离。

解题思路:

首先记录每个字母的位置。然后,从 A 开始,计算从当前字母到下一个字母的距离并累计。

C++代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)

void solved() {
    map<char, int> mp;
    string s;
    cin >> s;
    for (int i = 0; i < s.length(); i++) {
        mp[s[i]] = i;
    }
    int cnt = mp['A'];
    int ans = 0;
    for (int i = 1; i < 26; i++) {
        char go = 'A' + i;
        ans += abs(mp[go] - cnt);
        cnt = mp[go];
    }
    cout << ans << endl;
}

signed main() {
    close;
    solved();
    return 0;
}

C:Max Ai + Bj

题目链接:Max Ai + Bj

题目描述:

给定两个数组 A 和 B,找出 A 中最大的元素和 B 中最大的元素之和。

解题思路:

遍历数组 A 和 B,分别找到它们的最大值,然后输出这两个最大值的和。

C++代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)

void solved() {
    int n;
    cin >> n;
    vector<int> A(n), B(n);
    for (int i = 0; i < n; i++) cin >> A[i];
    for (int i = 0; i < n; i++) cin >> B[i];

    int maxA = *max_element(A.begin(), A.end());
    int maxB = *max_element(B.begin(), B.end());
    
    cout << maxA + maxB << endl;
}

signed main() {
    close;
    solved();
    return 0;
}


D:Hidden Weights

题目链接:Hidden Weights

题目描述:

给定一个有向图,包含N个节点和M条边,边有权重。对于每一条边,从节点u指向节点v,并有权重w,需要满足value[v] - value[u] = w。问题要求在所有节点之间赋值,并确保所有等式成立。

解题思路:

从根节点开始广度优先搜索(BFS),给根节点赋值0,然后根据边的权重推算其他节点的值。如果图不连通,则每个连通块单独进行 BFS。

C++代码实现:

#include<bits/stdc++.h>
using namespace std;
#define close ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
const int N = 2e5 + 10;
int vis[N];
vector<pair<int, int>> edg[N];
int n, m;
int v[N];

void bfs(int id) {
    queue<int> q;
    q.push(id);
    while(!q.empty()) {
        int who = q.front();
        q.pop();
        for(auto [ne, w] : edg[who]) {
            if(!vis[ne]) {
                vis[ne] = 1;
                v[ne] = v[who] + w;
                q.push(ne);
            }
        }
    }
}

void solved() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        edg[u].push_back({v, w});
        edg[v].push_back({u, -w});
    }
    for (int i = 1; i <= n; i++) {
        if(!vis[i]) {
            v[i] = 0;
            vis[i] = 1;
            bfs(i);
        }
    }
    for (int i = 1; i <= n; i++) {
        if(i > 1) {
            cout << " ";
        }
        cout << v[i];
    }
}

signed main() {
    close;
    solved();
    return 0;
}

E:How to Win the Election

题目链接:How to Win the Election

题目描述:

有N个人参加选举,一共有K张选票,最终会有M个人当选。部分票数已经确定,对于一个特定的候选人,计算他需要拿到的最少选票数以确保当选。

解题思路:

贪心策略:只需要关注那些能够对该候选人构成威胁的人,争取刚好进入前M名即可。

C++代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'

void solved()
{
    int n, m, k;
    cin >> n >> m >> k;
    vector<int> arr(n);
    int total = 0;
    for (auto &v : arr)
    {
        cin >> v;
        total += v;
    }
    int rem = k - total;
    if (n <= m)
    {
        for (int i = 0; i < n; i++)
        {
            if (i > 0)
            {
                cout << " ";
            }
            cout << 0;
        }
        cout << endl;
        return;
    }
    vector<int> brr(arr);
    sort(brr.begin(), brr.end());
    vector<int> index(n);
    iota(index.begin(), index.end(), 0);
    sort(index.begin(), index.end(), [&](int i, int j)
         { return arr[i] < arr[j]; });
    vector<int> pre(n + 1, 0);
    for (int i = 0; i < n; i++)
    {
        pre[i + 1] = pre[i] + brr[i];
    }
    vector<int> ans(n, -1);
    for (int i = 0; i < n; i++)
    {
        int l = 0, r = rem, result = -1;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            int right = upper_bound(brr.begin(), brr.end(), brr[i] + mid) - brr.begin();
            int left = n - m;
            if (i >= n - m)
            {
                --left;
            }
            int need = 0;
            if (right > left)
            {
                need += (right - left) * (brr[i] + mid + 1) - (pre[right] - pre[left]);
            }
            if (left <= i && i < right)
            {
                need--;
            }
            else
            {
                need += mid;
            }
            if (need <= rem)
            {
                l = mid + 1;
            }
            else
            {
            	result = mid;
                r = mid - 1;
            }
        }
        ans[index[i]] = result;
    }
    for (int i = 0; i < n; i++)
    {
        if (i > 0)
        {
            cout << " ";
        }
        cout << ans[i];
    }
    cout << endl;
}

signed main()
{
    close;
    solved();
    return 0;
}


F:Knapsack with Diminishing Values

题目链接:Knapsack with Diminishing Values

题目描述:

给定N种物品,每种物品的权重为w,价值为v。背包容量为W。某个物品的快乐值贡献为 kv - k*k,其中k为选取的个数。目标是让总快乐值最大化。

解题思路:

kv - k*k 拆解成多个项,发现每次多选一件物品的增量贡献为 v - 2。因此可以通过动态规划实现求解。

C++代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 30000;
const int inf = 1e18;

vector<int> edg[N];

void solved() {
    int N, W;
    cin >> N >> W;
    for (int i = 1; i <= N; i++) {
        int w, v;
        cin >> w >> v;
        edg[w].push_back(v);
    }

    vector<int> dp(W + 1, -inf);
    dp[0] = 0;
    
    for (int i = 1; i <= W; i++) {
        if (edg[i].empty()) {
            continue;
        }
        priority_queue<int> pq;
        for (int j = 0; j < edg[i].size(); j++) {
            pq.push(edg[i][j] - 1);
        }

        vector<int> happy(W / i + 1, 0);
        for (int nums = 0; nums < W / i; nums++) {
            int v = pq.top();
            pq.pop();
            happy[nums + 1] = happy[nums] + v;
            pq.push(v - 2);
        }

        for (int j = W; j >= 0; j--) {
            int nums = 1;
            while (j + nums * i <= W) {
                dp[j + nums * i] = max(dp[j + nums * i], dp[j] + happy[nums]);
                ++nums;
            }
        }
    }
    cout << *max_element(dp.begin(), dp.end()) << endl;
}

signed main() {
    close;
    solved();
    return 0;
}

G:No Cross Matching

题目链接:No Cross Matching

题目描述:

二维平面上有2*N个点,其中N个点在P集合中,N个点在Q集合中,问是否可以找到N条线段连接Pi和Qj,使这些线段两两之间没有交点。

解题思路:

可以将该问题转化为最小流问题,证明线段不相交的最优条件是满足 ac + bd <= ab + cd,即找到一组连接使得总距离最小。

C++代码实现:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 1000010;
const int inf = 1e18;
const long double C = 1.5e12;

struct Edg
{
    int next, to, cap, cost;
};

Edg edg[N];
int head[N], tot = 1;
int h[N], dist[N], prePoint[N], preEdg[N];
int n, s, t;
vector<pair<int, int>> point[2];
void input()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x, y;
        cin >> x >> y;
        point[0].push_back({x, y});
    }
    for (int i = 1; i <= n; i++)
    {
        int x, y;
        cin >> x >> y;
        point[1].push_back({x, y});
    }
}
inline long double dis(pair<int, int> a, pair<int, int> b)
{
    return sqrt((a.first - b.first) * (a.first - b.first) + 
                (a.second - b.second) * (a.second - b.second));
}
void add(int u, int v, int cap, int cost)
{
    edg[++tot] = {head[u], v, cap, cost};
    head[u] = tot;
    edg[++tot] = {head[v], u, 0, -cost};
    head[v] = tot;
}
void build()
{
    s = 2 * n;
    t = 2 * n + 1;
    for (int i = 0; i < n; i++)
    {
        add(s, i, 1, 0);
    }
    for (int i = 0; i < n; i++)
    {
        add(i + n, t, 1, 0);
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int cost = (int)(dis(point[0][i], point[1][j]) * C + 0.5);
            add(i, j + n, 1, cost);
        }
    }
}
int minFlow(int s, int t, int limit)
{
    int flow = 0, cost = 0;
    while (flow < limit)
    {
        fill(dist, dist + N, inf);
        dist[s] = 0;
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
        pq.push({0, s});
        while (!pq.empty())
        {
            auto [d, v] = pq.top();
            pq.pop();
            if (dist[v] < d)
                continue;
            for (int i = head[v]; i; i = edg[i].next)
            {
                Edg &e = edg[i];
                if (e.cap > 0)
                {
                    int to = e.to;
                    int cost_vw = e.cost + h[v] - h[to];
                    if (dist[to] > dist[v] + cost_vw)
                    {
                        dist[to] = dist[v] + cost_vw;
                        prePoint[to] = v;
                        preEdg[to] = i;
                        pq.emplace(dist[to], to);
                    }
                }
            }
        }
        if (dist[t] == inf)
        {
            break;
        }
        for (int v = 0; v <= t; ++v)
        {
            if (dist[v] < inf)
                h[v] += dist[v];
        }
        int cnt = limit - flow;
        for (int v = t; v != s; v = prePoint[v])
        {
            cnt = min(cnt, edg[preEdg[v]].cap);
        }
        flow += cnt;
        cost += cnt * h[t];
        for (int v = t; v != s; v = prePoint[v])
        {
            edg[preEdg[v]].cap -= cnt;
            edg[preEdg[v] ^ 1].cap += cnt;
        }
    }
    if (flow < limit)
    {
        cout << "-1" << endl;
        exit(0);
    }
    return cost;
}
void output()
{
    vector<int> ans(n, -1);
    for (int i = 0; i < n; ++i)
    {
        for (int e = head[i]; e; e = edg[e].next)
        {
            Edg &ed = edg[e];
            if (ed.to >= n && ed.to < 2 * n && ed.cap == 0)
            {
                ans[i] = ed.to - n + 1;
                break;
            }
        }
    }
    for (int i = 0; i < n; ++i)
    {
        cout << ans[i] << " \n"[i == n - 1];
    }
}
signed main()
{
    close;
    input();
    build();
    int limit = n;
    int minCost = minFlow(s, t, limit);
    output();
    return 0;
}

以上是对 AtCoder Beginner Contest 373 中所有题目的解题思路和代码实现,希望对你有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值