URL:https://atcoder.jp/contests/abc301
目录
A
Problem/题意
给一个只含 A 或 T 的字符串,如果 A 多,输出 A;如果 T 多,输出 T。如果一样多,从左到右数,谁先数完输出谁。
Thought/思路
好难,没有思路。
Code/代码
#include "bits/stdc++.h"
signed main() {
int n; std::cin >> n;
std::string s; std::cin >> s;
int a = 0, t = 0;
for (int i = 0; i < s.length(); ++ i) {
if (s[i] == 'T') t ++;
if (s[i] == 'A') a ++;
}
if (t == a) {
int ra = 0, rt = 0;
for (int i = 0; i < s.length(); ++ i) {
if (s[i] == 'T') rt ++;
if (s[i] == 'A') ra ++;
if (rt == t) {
std::cout << "T\n";
break;
}
if (ra == a) {
std::cout << "A\n";
break;
}
}
} else {
if (t > a) std::cout << "T\n";
else std::cout << "A\n";
}
}
B
Problem/题意
给一个序列a,进行下面两种操作:
1.若 a[i] > a[i + 1],在 i 和 i + 1 之间插入 a[i] 和 a[i + 1] 之间所有的数,满足递减;
2.若 a[i] < a[i + 1],在 i 和 i + 1 之间插入 a[i] 和 a[i + 1] 之间所有的数,满足递增;
Thought/思路
写在题意里了。
Code/代码
#include "bits/stdc++.h"
signed main() {
int n; std::cin >> n;
std::vector <int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
std::cout << a[1] << " ";
for (int i = 2; i <= n; ++ i) {
if (a[i - 1] > a[i]) {
for (int j = a[i - 1] - 1; j >= a[i]; -- j)
std::cout << j << " ";
} else if (a[i - 1] < a[i]) {
for (int j = a[i - 1] + 1; j <= a[i]; ++ j)
std::cout << j << " ";
} else {
std::cout << a[i] + 1 << " " << a[i] << " ";
}
}
}
C
Problem/题意
给两个由 小写字母 和 @ 组成的字符串,其中 @ 可以用(a、t、c、o、d、e、r)替换,问替换后两个串能否一致。
Thought/思路
先记录两个串中的字符出现的次数cnt,然后把相同的先减去。
然后两个 cnt 数组分别判断:如判断S串,当遇到某个字符的 cnt 不为 0,就去查看这个字符能否由 @ 转换,并且要求 T 串的 @ 的 cnt 大于等于 这个字符的 cnt。
Code/代码
#include "bits/stdc++.h"
int cnts[27], cntt[27];
signed main() {
std::string s; std::cin >> s;
std::string t; std::cin >> t;
for (int i = 0; i < s.length(); ++ i) {
if (s[i] == '@') cnts[26] ++;
else cnts[s[i] - 'a'] ++;
if (t[i] == '@') cntt[26] ++;
else cntt[t[i] - 'a'] ++;
}
for (int i = 0; i < 26; ++ i) { // @ 不用减
int tmp = std::min(cntt[i], cnts[i]);
cntt[i] -= tmp;
cnts[i] -= tmp;
}
// for (int i = 0; i <= 26; ++ i) std::cout << cnts[i] << " ";
// std::cout << "\n";
// for (int i = 0; i <= 26; ++ i) std::cout << cntt[i] << " ";
// std::cout << "\n";
int get[7] = {'a' - 'a', 't' - 'a', 'c' - 'a', 'o' - 'a', 'd' - 'a', 'e' - 'a', 'r' - 'a'};
bool ans = true;
for (int i = 0; i < 26; ++ i) {
if (cnts[i] > 0) {
bool flag = false;
for (int j = 0; j < 7; ++ j) {
if (get[j] == i) flag = true;
}
if (flag and cntt[26] >= cnts[i]) {
cntt[26] -= cnts[i];
} else {
ans = false;
//std::cout << "error in s\n";
}
}
}
for (int i = 0; i < 26; ++ i) {
if (cntt[i] > 0) {
bool flag = false;
for (int j = 0; j < 7; ++ j) {
if (get[j] == i) flag = true;
}
if (flag and cnts[26] >= cntt[i]) {
cnts[26] -= cntt[i];
} else {
ans = false;
//std::cout << "error in t\n";
}
}
}
if (ans) std::cout << "Yes\n";
else std::cout << "No\n";
}
D
Problem/题意
给一个由 0、1、? 组成的字符串,给一个数 n,问:将 ?换成 0 或 1 后,最接近(<=)n 的数是多少?若没有,输出 -1。
Thought/思路
显然是贪心,先把原来的1全部算上,然后判断一次是否 <= n,若 <= n,则从最高位开始判断。
若该位是 ?,且置为 1 后仍 <= n,那么这一位就可以变成 1。
注意:
最好 reverse 一下字符串。
Code/代码
#include "bits/stdc++.h"
#define int long long
int n;
std::string t;
char s[70];
signed main() {
std::cin >> t >> n;
for (int i = t.length() - 1; i >= 0; -- i) {
s[t.length() - i - 1] = t[i];
}
int tmp = 0;
for (int i = 0; i < t.length(); ++ i) {
if (s[i] == '1') {
tmp = tmp | (1ll << i);
}
}
if (tmp > n) {
std::cout << -1;
return 0;
}
std::vector <int> v;
v.push_back(tmp);
for (int i = t.length() - 1; i >= 0; -- i) {
if (s[i] == '?') {
if ((tmp | (1ll << i)) <= n) {
tmp = tmp | (1ll << i);
v.push_back(tmp);
}
}
}
std::cout << v[v.size() - 1] << "\n";
}
E
Problem/题意
给一个矩阵,上面有“起点”、“终点”、“墙”、“糖”。在最多行走 T 次的条件下,能最多吃到多少颗糖。
Thought/思路
1.注意到糖的数量很少,最多18颗。
因此,我们可以用 18 个二进制位,来表示“糖的获取情况”。比如一共有 5 颗糖,此时糖的获取情况 num = 10,而 10 转换成二进制数就是 01010,这就表示,第二、四颗糖已经获取了。
2.用 dp[num][i] 表示“从起点出发,当前获取的糖的情况为 s,此时停留在18颗糖中的第 i 颗糖”的最短距离。
3.所以,最后只要求出每颗糖到终点的最短距离 dis[i][end],然后判断每个 dp[num][i] + dis[i][end] <= T 即可。
4.所以,最难的问题就在于,dp应该怎么更新。
在这之前,我们用18次“bfs”求出“每颗糖果到其他所有点的距离”,如:dis[i][x][y]表示“糖 i 到点(x,y)的距离”。可见,dis需要用一个三维数组存储。
最简单也是最初始的情况是:“从起点出发,每种情况都只获取了一颗糖”。即:二进制数上只有一个“1”。也就是令:
dp[1 << i][i] = dis[i][sx][sy],(i = 0,1,2,.....,17)
因此,肯定是用糖果少的情况,去拓展糖果多的情况。
比如:
当我们确定一个“糖果获取情况num”和“当前所在的糖果j”,那么,我们只需要遍历一遍num的二进制位,就能知道:二进制位为“1”糖果已经包含在“num”中,二进制位为“0”的糖果没有包含在“num”中。
选择没有包含在“num”中的糖果进行拓展,此时判断:从第j颗糖果出发,加上“第j颗糖果到第k颗糖果的最短路”(之前的bfs已经求出了),能否比dp[num | (1 << k)][k]更小,若更小,则更新。
加以代码理解:
for (int i = 1; i <= (1ll << cnt) - 1; ++ i) { // cnt是糖果数量
for (int j = 0; j < cnt; ++ j) {
if (dp[i][j] == INF) continue; // 说明这种情况还没有遇到过,不能用
for (int k = 0; k < cnt; ++ k) {
if ((i >> k) & 1) continue; // 已经包含的,跳过
int x = candy[k].first, y = candy[k].second;
if (dp[i | (1 << k)][k] > dp[i][j] + dis[j][x][y]) {
dp[i | (1 << k)][k] = dp[i][j] + dis[j][x][y];
}
}
}
}
Code/代码
#include "bits/stdc++.h"
typedef std::pair <int, int> pii;
const int INF = (int)1e9;
int h, w, t, vis[307][307];
char mp[307][307];
int dir[5] = {0, 1, 0, -1, 0};
std::vector <pii> candy;
std::vector <std::vector <int>> dis[20];
bool check(int x, int y) {
if (x < 1 or x > h or y < 1 or y > w or mp[x][y] == '#' or vis[x][y]) return true;
else return false;
}
std::vector <std::vector <int>> bfs(int x, int y) {
std::vector <std::vector <int>> res(307, std::vector <int> (307, INF));
memset(vis, 0, sizeof vis);
std::queue <pii> q;
q.push({x, y});
res[x][y] = 0;
while (!q.empty()) {
auto top = q.front(); q.pop();
int x = top.first, y = top.second;
if (vis[x][y]) continue;
vis[x][y] = 1;
for (int i = 0; i <= 3; ++ i) {
int nx = x + dir[i], ny = y + dir[i + 1];
if (check(nx, ny)) continue;
if (res[nx][ny] > res[x][y] + 1) {
res[nx][ny] = res[x][y] + 1;
q.push({nx, ny});
}
}
}
return res;
}
signed main() {
std::cin >> h >> w >> t;
int sx = 0, sy = 0; // 起点
int ex = 0, ey = 0; // 终点
for (int i = 1; i <= h; ++ i) {
for (int j = 1; j <= w; ++ j) {
std::cin >> mp[i][j];
if (mp[i][j] == 'S') {
sx = i, sy = j;
}
if (mp[i][j] == 'o') {
candy.push_back({i, j});
}
if (mp[i][j] == 'G') {
ex = i, ey = j;
}
}
}
int cnt = candy.size();
for (int i = 0; i < cnt; ++ i) {
dis[i] = bfs(candy[i].first, candy[i].second); // 求出糖果i到其他位置的最短距离
}
std::vector <std::vector <int>> dp(1ll << cnt, std::vector <int>(20, INF));
for (int i = 0; i < cnt; ++ i) {
dp[1ll << i][i] = dis[i][sx][sy]; // 初始化每个糖果到起点的距离
}
for (int i = 1; i <= (1ll << cnt) - 1; ++ i) {
for (int j = 0; j < cnt; ++ j) {
if (dp[i][j] == INF) continue;
for (int k = 0; k < cnt; ++ k) {
if ((i >> k) & 1) continue;
int x = candy[k].first, y = candy[k].second;
if (dp[i | (1 << k)][k] > dp[i][j] + dis[j][x][y]) {
dp[i | (1 << k)][k] = dp[i][j] + dis[j][x][y];
}
}
}
}
int ans = -1;
std::vector <std::vector <int>> none = bfs(sx, sy); // 计算起点到其他点距离
if (none[ex][ey] <= t) ans = 0; // 能到终点
for (int i = 1; i <= (1ll << cnt) - 1; ++ i) {
for (int j = 0; j < cnt; ++ j) {
if (dp[i][j] + dis[j][ex][ey] <= t) {
int num = 0;
for (int k = 0; k < cnt; ++ k) {
if ((i >> k) & 1) num ++;
}
ans = std::max(ans, num);
}
}
}
std::cout << ans;
}