首页 > 其他分享 >AtCoder ABC 369题解

AtCoder ABC 369题解

时间:2024-09-03 21:14:20浏览次数:12  
标签:AtCoder ABC 200005 int 题解 金币 code using include

前言

本题解部分思路来源于网络,仅供参考

A - 369

题目大意

给定 \(A\) , \(B\) 两个整数,求有多少个整数 \(x\) 使得

  • 可以通过某种排列使得 \(A\) ,\(B\) ,\(x\) 为等差数列。

解题思路

稍加分析即可得到:

  • 如果 \(A = B\) 则结果为 \(1\) 。

  • 如果 \(A = B\) 但 \((A + B) \bmod 2 = 1\) 则结果为 \(2\) 。

  • 否则,结果为 \(3\) 。

code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int a, b;
    scanf("%d%d", &a, &b);
    if (a == b) printf("1\n");
    else if ((a + b) % 2 == 1) printf("2\n");
    else printf("3\n");
    return 0;
}

B - Piano 3

题目大意

高桥有一架有 \(100\) 个键的钢琴,给定一个操作序列,按如下操作计算出操作完成后的疲劳程度。

  • 当手从 \(a\) 移动到 \(b\) 时,疲劳程度增加 \(\left| a-b \right|\) 。

解题思路

根据题目模拟即可。

code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int flag1 = 1, flag2 = 1, ll, lr, ans = 0;
    int a, n;
    char c;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d %c", &a, &c);
        if (c == 'L') {
            if (flag1) {
                ll = a;
                flag1 = 0;
            } else {
                ans += abs(a - ll);
                ll = a;
            }
        } else {
            if (flag2) {
                lr = a;
                flag2 = 0;
            } else {
                ans += abs(a - lr);
                lr = a;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

C - Count Arithmetic Subarrays

题目大意

给定长度为 \(N\) 的数列 \(\left(A_1,A_2,...\ ,A_N\right)\) ,求有多少个数对 \((l,r)\quad1 \leqslant l \leqslant r \leqslant N\) 使得数列 \((A_l,A_{l + 1},...\ ,A_r)\) 为等差数列。

解题思路

可以通过遍历一遍数组,查找每个等差数列,然后组合计数。具体见代码。

code

#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
    int n;
    int ans = 0, la, d = 0x3f3f3f3f, a, cnt = 1;
    scanf("%lld%lld", &n, &la);
    for (int i = 2; i <= n; i++) {
        scanf("%lld", &a);
        if (a - la != d) {
            ans += cnt * (cnt - 1) / 2 + cnt - 1;
            cnt = 2;
            d = a - la;
        } else {
            cnt++;
        }
        la = a;
    }
    ans += cnt * (cnt - 1) / 2 + cnt;
    printf("%lld\n", ans);
    return 0;
}

D - Bonus EXP

题目大意

高桥打怪,如果这是打的第偶数个怪物,则获得双倍积分,否则只获得一份积分。放走怪物不获得积分。求如何获得最大积分?

解题思路

题目可以整理成如下图:

第 \(i\) 列节点(从 \(0\) 开始标号)代表在杀死或放走第 \(i\) 只怪物后获得的积分总数。第 \(1/2\) 行节点代表 \(1/2\) 倍的积分。只要填好每一个节点上的数,就可以求出答案。

code

#include <bits/stdc++.h>
using namespace std;
long long dp[200005][2];
signed main() {
    int n;
    scanf("%d", &n);
    dp[0][1] = -0x3f3f3f3f;
    for (int i = 1, a; i <= n; i++) {
        scanf("%d", &a);
        for (int j = 0; j <= 1; j++) {
            dp[i][j] = max(dp[i][j], dp[i - 1][j]);
            dp[i][1 - j] = max(dp[i][1 - j],
                               dp[i - 1][j] + a * (j + 1));
        }
    }
    printf("%lld\n", max(dp[n][0], dp[n][1]));
    return 0;
}

E - Sightseeing Tour

题目大意

给定一个图,想从 \(1\) 节点走到 \(N\) 节点,但是有几条路径必须经过,求最短路径。

解题思路

可以先对这个图进行 Floyed 求出两个节点之间的关系,然后枚举每一条钦定路径的顺序,方向,求出每一种方案的最短路径,最后输出长度最短的结果。

code

#include <bits/stdc++.h>
#include <climits>
#include <cstdio>
using namespace std;
using ll = long long;
ll dis[405][405];
ll u[200005], v[200005], w[200005];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    memset(dis, 0x3f, sizeof(dis));
    for (int i = 1; i <= n; i++) {
        dis[i][i] = 0;
    }
    for (int i = 1; i <= m; i++) {
        scanf("%lld%lld%lld", &u[i], &v[i], &w[i]);
        dis[v[i]][u[i]] = dis[u[i]][v[i]] =
            min(dis[u[i]][v[i]], w[i]);
    }
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                dis[i][j] =
                    min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
    int q;
    scanf("%d", &q);
    while (q--) {
        int k, id[6];
        scanf("%d", &k);
        for (int i = 1; i <= k; i++) {
            scanf("%d", id + i);
        }
        sort(id + 1, id + 1 + k);
        ll ans = LLONG_MAX;
        do {
            for (int j = 0; j < (1 << k); j++) {
                ll cur = 0;
                for (int i = 1; i <= k; i++) {
                    cur += w[id[i]];
                }
                for (int i = 1; i <= k + 1; i++) {
                    cur += dis[i == 1 ? 1
                               : (j >> (i - 2)) & 1
                                   ? v[id[i - 1]]
                                   : u[id[i - 1]]]
                              [i > k ? n
                               : (j >> (i - 1)) & 1
                                   ? u[id[i]]
                                   : v[id[i]]];
                }
                ans = min(ans, cur);
            }
        } while (next_permutation(id + 1, id + 1 + k));
        printf("%lld\n", ans);
    }
    return 0;
}

F - Gather Coins

题目大意

给定一个表格,表格上有一些金币,经过有金币的格子会自动拾取金币,而且只能向下的向右行走,求怎么走可以使拾取的金币最多,并输出最多可以拾取的金币数量。

解题思路

这道题是一道动态规划,令 \(dp_i\) 为遇到第 \(i\) 个金币时,最大拾取的金币个数。

因为第 \(i - 1\) 个金币在第 \(i\) 个金币的左上方,所以可以把所有金币按横轴排序,至于纵轴,可以通过树状数组维护。有了第 \(i\) 个节点左上方的金币个数,则动态转移方程为:

\[dp_i = \max \limits_{\substack{x_j \leqslant x_i \\ y_j \leqslant x_i}} \left\{dp_j\right\} \]

code

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
using PII = pair<int, int>;
int h, w, n;
PII p[200005], dp[200005];
PII f[200005];
void modify(PII x, int pos) {
    while (pos <= w) {
        f[pos] = max(f[pos], x);
        pos += pos & -pos;
    }
}
PII query(int pos) {
    PII res{-1, 0};
    while (pos) {
        res = max(res, f[pos]);
        pos -= pos & -pos;
    }
    return res;
}
int main() {
    scanf("%d%d%d", &h, &w, &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &p[i].fi, &p[i].se);
    p[0] = {1, 1};
    p[n + 1] = {h, w};
    sort(p + 1, p + 1 + n);
    for (int i = 1; i <= n; i++) {
        f[i] = {INT_MIN, 0};
    }
    modify(dp[0], 1);
    for (int i = 1; i <= n + 1; i++) {
        dp[i] = query(p[i].se);
        modify({++dp[i].fi, i}, p[i].se);
    }
    printf("%d\n", dp[n + 1].fi - 1);
    string ans;
    for (int i = n + 1; i; i = dp[i].se) {
        for (int j = 1; j <= p[i].fi - p[dp[i].se].fi; j++)
            ans += 'D';
        for (int j = 1; j <= p[i].se - p[dp[i].se].se; j++)
            ans += 'R';
    }
    reverse(ans.begin(), ans.end());
    cout << ans << endl;
    return 0;
}

标签:AtCoder,ABC,200005,int,题解,金币,code,using,include
From: https://www.cnblogs.com/sxloiblog/p/18395477

相关文章

  • 09-03 题解
    09-03题解比赛地址补题地址这回打算改变一下方式,从写"怎么做题"变成"怎么想题"T1什么样的两个\(a_i\)能被合并到一个Bug上?很简单(不过我也想了好一会),mod2同余的两个可以合并在一起为了培养最强Bug,肯定不能往上叠负数,所以上述内容针对序列中的所有正......
  • [蓝桥杯 2018 省 A] 付账问题--贪心题解
    题目重述:[蓝桥杯2018省A]付账问题-洛谷#[蓝桥杯2018省A]付账问题##题目描述几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。现在有$n$个人出去吃饭,他们总共消费了$S$元。其中第$i$个人带了$a_i$元。幸运的是,所有人带的钱的总数是......
  • 蓝桥杯2019省A糖果题解
     附上链接:[蓝桥杯2019省A]糖果-洛谷,有兴趣的小伙伴可以去试试哦~#[蓝桥杯2019省A]糖果##题目描述糖果店的老板一共有$M$种口味的糖果出售。为了方便描述,我们将$M$种口味编号$1$∼$M$。小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而......
  • [ABC369G] As far as possible
    考虑删除树上一条边\((u,v,l)\),此时剩余部分构成两个连通块,如果不包含节点\(1\)的连通块中有Aoki选择的点,那个这条边的贡献至少为\(2l\)。简单构造发现,当Takahashi构造的路径恰好为Aoki选择的点和\(1\)构成的虚树时,能够取到路径长度的最小值。此时我们将题目转......
  • 8.30 上午 becoder 模拟赛总结 & 题解
    T1密码当时想到解法了,却依然认为自己不会做,我真是个人才。结论:对于$\foralli\in[1,n)$,满足密码不是$a_i$的因数,且密码是$a_k$的因数,设满足条件的最小值为$g$则答案为$\frac{n}{g}$。一种最好想的做法:枚举$\gcd(a_k,n)$的因数作为$g$,并枚举$i\in[1,n)$,判断是......
  • 8.31 上午 becoder 模拟赛总结 & 题解
    T1四个质数的和赛场亲测搜索+小剪枝可以得到70pts。考虑$O(p(V)^2)$枚举任意两个质数的和,其中$p(V)$表示$V$以内质数的个数。然后开个数组记录下对于每种和的记录有多少种情况,查询时for循环扫一遍即可,详见代码。复杂度去掉质数筛$O(p(V)^2+tn)$,代码贴在下面(100pts)......
  • 8.31 下午 梦熊联盟 NOIP 模拟赛总结 & 题解
    T1北极星一个比较好想到的点是从后往前枚举数,计算得出它需要的操作次数,然后给所有前面的数都加上这个操作次数,这样就把每个数独立出来了。所以这道题就变成了如何快速通过这些操作得到一个指定的数。观察大样例的输出,发现每一个数都是11?1?1?的形式,其中问号为+或c,我们可......
  • 9.1 上午 becoder 模拟赛总结 & 题解
    T1货车运输Kruskal重构树模板,没什么好说的,不会的把自己重构了算了,跳过。T2Slagalica可以发现拼图1和2、3拼起来还是拼图1,拼图4和2、3拼起来也还是拼图4,这两种拼图还都不能和自己拼,所以我们可以看作只有拼图1和拼图4来做。对于边界拼图分别是5、7的情况,只有......
  • 8.31 晚上 ABC369 总结 & 题解
    打了一天的比赛。ABCD太水了,直接放代码链接得了,点字母就能看对应代码。E-SightseeingTour看范围$N$只有$400$,所以我们可以先用floyd搞出任意两点间的距离。对于每次询问,发现$K_i$只有$5$,所以可以直接深搜应该走哪座桥,和应该走到哪一端。时间复杂度$O(N3+QK_i......
  • 9.2 上午 becoder 模拟赛总结 & 题解
    T1加法最开始看了好久没想出来,先做T2去了,然后回来想了一会儿发现自己可能智商有点问题。看到求最小值最大,第一反应肯定是二分,那我们怎么应该怎么check呢?考虑顺次枚举序列$A$中的每一个数,然后如果这个数没有达到mid的要求,我们肯定是要添加区间的。那么我们怎么添加区......