前言
本题解部分思路来源于网络,仅供参考 !
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\) 个节点左上方的金币个数,则动态转移方程为:
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;
}