「解题报告」Toyota Programming Contest 2023#4(AtCoder Beginner Contest 311)
比赛地址:Toyota Programming Contest 2023#4(AtCoder Beginner Contest 311) - AtCoder
后记:大家都太强了%%%,如果我做不出第四题就要掉分了。。。
A - First ABC
找到第一个 \(\texttt{A, B, C}\) 三种字符都出现的位置。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 110;
int n, fga, fgb, fgc;
char s[N];
int main() {
n = read<int>();
scanf("%s", s + 1);
for (int i = 1; i <= n; ++ i) {
if (s[i] == 'A') fga = 1;
if (s[i] == 'B') fgb = 1;
if (s[i] == 'C') fgc = 1;
if (fga && fgb && fgc) {
cout << i << '\n';
break ;
}
}
return 0;
}
B - Vacation Together
B - Vacation Together (atcoder.jp)
找到最长的连续的区间,使得区间里全为 \(\texttt{o}\)。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 110;
int n, d, ans, mx;
char s[N][N];
int main() {
n = read<int>(), d = read<int>();
for (int i = 1; i <= n; ++ i) {
scanf("%s", s[i] + 1);
}
for (int i = 1; i <= d; ++ i) {
int fg = 1;
for (int j = 1; j <= n; ++ j) {
if (s[j][i] == 'x') {
fg = 0;
break ;
}
}
if (fg == 0) {
mx = max(mx, ans);
ans = 0;
}
ans += fg;
}
cout << max(mx, ans) << '\n';
return 0;
}
C - Find it!
一个找环问题,拓扑排序 + dfs 即可。
这个蒟蒻因为忘记统计入度而罚了两罚。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 2e5 + 5;
int n;
int in[N];
vector<int> e[N], ans;
queue<int> q;
bitset<N> vis;
void print() {
cout << ans.size() << '\n';
for (int v : ans) {
cout << v << ' ';
}
}
void dfs(int u) {
if (vis[u]) {
print();
exit(0);
}
ans.emplace_back(u);
vis.set(u);
for (int v : e[u]) {
dfs(v);
}
ans.pop_back();
vis.reset(u);
}
int main() {
n = read<int>();
for (int i = 1, x; i <= n; ++ i) {
e[i].emplace_back(x = read<int>());
++ in[x]; // 就是这里!
}
for (int i = 1; i <= n; ++ i) {
if (!in[i]) {
q.emplace(i);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : e[u]) {
-- in[v];
if (!in[v]) {
q.emplace(v);
}
}
}
for (int i = 1; i <= n; ++ i) {
if (in[i]) {
dfs(i);
break ;
}
}
return 0;
}
D - Grid Ice Floor
D - Grid Ice Floor (atcoder.jp)
一道考验搜索能力的题,我用的广搜,存储下每个节点的方向,防止重复。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 210;
const int dx[5] = {0, 0, 1, 0, -1};
const int dy[5] = {0, 1, 0, -1, 0};
int n, m;
char s[N][N];
bool vis[N][N][5], ok[N][N];
struct node {
int x, y, dir;
};
void bfs() {
queue<node> q;
q.push(node{2, 2, 0});
while (!q.empty()) {
node fr = q.front();
q.pop();
int x = fr.x, y = fr.y, dir = fr.dir;
if (vis[x][y][dir]) continue ;
ok[x][y] = 1;
vis[x][y][dir] = 1;
if (dir == 0) {
for (int i = 1; i <= 4; ++ i) {
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 1 && yy >= 1 && xx <= n && yy <= m && s[xx][yy] == '.') {
q.push(node{xx, yy, i});
}
}
continue ;
}
if (x + dx[dir] >= 1 && y + dy[dir] >= 1 && x + dx[dir] <= n && y + dy[dir] <= m) {
if (s[x + dx[dir]][y + dy[dir]] == '.') {
q.push(node{x + dx[dir], y + dy[dir], dir});
}
else {
q.push(node{x, y, 0});
}
}
}
}
int main() {
n = read<int>(), m = read<int>();
for (int i = 1; i <= n; ++ i) {
scanf("%s", s[i] + 1);
}
bfs();
int ans = 0;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
if (ok[i][j]) {
++ ans;
}
}
}
cout << ans << '\n';
return 0;
}
E - Defect-free Squares
E - Defect-free Squares (atcoder.jp)
用 DP 来解决问题。
设 \(dp\left( i, j\right)\) 代表右下角为 \(\left( i, j \right)\) 的无孔正方形的最大边 \(n\),如果不存在这样的正方形,则为 \(0\)。
设答案为 \(ans\),则
证明,如果 \(dp \left(i, j \right) = k\),那么一定存在右下角为 \(\left(i, j \right)\) 的长度为 \(1, 2 \dots k\) 的正方形是无孔正方形。
递推式:
小小的说明:
大小为 \(n\) 的正方形区域,其右下角正方形为 \((i,j)\),是无孔的。
大小为 \((n−1)\) 的正方形区域,其右下角为 \((i,j−1)\),是无孔的。
大小为 \((n−1)\) 的正方形区域,其右下角为 \((i−1,j)\),是无孔的。
大小为 \((n−1)\) 的正方形区域,其右下角为 \((i−1,j)\),是无孔的。
\((i,j)\)没有孔。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 3010;
int h, w, n;
ll dp[N][N];
bool hole[N][N];
int main() {
h = read<int>(), w = read<int>(), n = read<int>();
for (int i = 1, a, b; i <= n; ++ i) {
a = read<int>(), b = read<int>();
hole[a][b] = 1;
}
ll ans = 0;
for (int i = 1; i <= h; ++ i) {
for (int j = 1; j <= w; ++ j) {
if (hole[i][j]) continue ;
dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;
ans += dp[i][j];
}
}
cout << ans << '\n';
return 0;
}
还有一位大佬的暴力写法也过了,纯暴力是 \(n^3\) 的,这位大佬优化了枚举边的复杂度,使得他的代码跑过去了,下面展示一下。
#include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"
using namespace std;
//constexpr long long int MOD = 1000000007;
constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-8;
//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> H >> W;
vector<vector<int>>sum(H + 1, vector<int>(W + 1));
cin >> N;
for (int i = 0; i < N; i++) {
int y, x;
cin >> y >> x;
sum[y][x]++;
}
for (int i = 0; i <= H; i++) {
for (int j = 1; j <= W; j++) {
sum[i][j] += sum[i][j - 1];
}
}
for (int i = 1; i <= H; i++) {
for (int j = 0; j <= W; j++) {
sum[i][j] += sum[i - 1][j];
}
}
long long ans = 0;
for (int i = 0; i < H; i++) {
int bef = 0;
for (int j = 0; j < W; j++) {
int ok = bef - 1;
for (int k = max(0, bef - 1); i + k <= H && j + k <= W; k++) {
int num = sum[i + k][j + k] - sum[i][j + k] - sum[i + k][j] + sum[i][j];
if (num == 0) {
ok = k;
} else {
break;
}
}
ans += ok;
bef = ok;
}
}
cout << ans << endl;
}
F - Yet Another Grid Task
F - Yet Another Grid Task (atcoder.jp)
一个 \(n \times m\) 的网格,每个格子是黑色的或白色的,一个网格被认为是漂亮的,当且仅当 \((i, j)\) 为黑色时,\((i + 1, j)\) 和 \((i + 1, j + 1)\) 也是黑色的,问有多少种方法使得这个网格变成漂亮的(可以把白色染成黑色),对方案数模上 \(998244353\)。
实在是看不懂了,尽我所能了,下面是一份 AC 代码,但不是我写的,也不是题解的做法,有理解的可以在评论区评论。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 2010;
const int mod = 998244353;
int n, m;
int h[N];
ll g[N][N], f[N][N];
char s[N][N];
int main() {
n = read<int>(), m = read<int>();
for (int i = 1; i <= n; ++ i) {
scanf("%s", s[i] + 1);
}
for (int j = 1; j <= m; ++ j) {
h[j] = n + 1;
for (int i = 1; i <= n; ++ i) {
if (s[i][j] == '#') {
h[j] = i;
break ;
}
}
}
f[0][n + 1] = 1;
for (int i = 0; i <= n + 1; ++ i) {
g[0][i] = 1;
}
for (int i = 1; i <= m; ++ i) {
for (int j = 1; j <= h[i]; ++ j) {
f[i][j] = g[i - 1][j - 1];
}
for (int j = n + 1; ~j; -- j) {
g[i][j] = (g[i][j + 1] + f[i][j]) % mod;
}
}
cout << g[m][1] << '\n';
return 0;
}