前言
本题解部分思路来源于网络,仅供参考 !
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