AtCoder Beginner Contest 311 A-E题解
A - First ABC
题意
给一个长度为N的仅由ABC三个字符组成的字符串S,问S中ABC三个字符第一次出现的位置的最大值。
题解
使用map<char,bool>
判重,记录当前不同的字符串的个数cnt
,当cnt
等于3时,输出此时的下标+1作为答案。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define lowbit(x) ((x) & -(x))
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1 ) | 1)
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int t = 1;
string s;
int n;
cin >> n;
cin >> s;
map<char,bool> mp;
int cnt = 0;
FOR (i, 0, SZ(s)) {
if (!mp[s[i]]) {
cnt++;
mp[s[i]] =1;
}
if (cnt == 3) {
cout << i +1 << "\n";
return 0;
}
}
return 0;
}
B - Vacation Together
题意
给出N个人的接下来D天的日程表,问这D天中,N个人都连续空闲的天数的最大值。
题解
使用cnt
记录当前连续空闲的时长,mx
记录答案。对于每一天,都判断N个人是否空闲,如果空闲就cnt++
,否则就拿现在的天数与mx
取最大值,cnt
恢复为0.
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define lowbit(x) ((x) & -(x))
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1 ) | 1)
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int n, d;
cin >> n>> d;
vector<string> v(n);
FOR (i, 0, n) cin >> v[i];
int cnt = 0, mx = 0;
FOR (i, 0, d) {
bool ok = 1;
FOR (j, 0, n) {
if (v[j][i] == 'x') {
ok = 0;
}
}
if (ok) {
cnt ++;
} else {
mx = max(cnt, mx);
cnt = 0;
}
}
mx = max(mx, cnt);
cout << mx << "\n";
return 0;
}
C - Find it!
题意
给出有N个点N条边的有向图,问图中是否存在有向的环,如果存在多个,任意一个都可作为答案。
题解
使用链式前向星记录有向图,使用第一个dfs
找到环中的一个点,由于进了有向环就不会再出这个环(这个是每个点只有一条出边保证的),所以再通过 dfs2
遍历这个环即可。
对于如何找到环中的点,我们可以在dfs
的过程中记录这个点是否在此次dfs
中出现过,如果一个点出现了两次,说明我们进入了一个有向的环,这个出现两次的点一定在环中。
对于如何使用dfs2
记录环中的点,类似于dfs
,一直记录点是否出现过,边记录边放进数组中,如果一个点出现了两次,说明环已经遍历完了。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define lowbit(x) ((x) & -(x))
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define SZ(x) (int)(x.size())
#define FOR(i, x, y) for (int i = (x), _##i = (y); i < _##i; i++)
#define FORD(i, x, y) for (int i = (x), _##i = (y); i > _##i; i--)
const int N = 2e5 + 10;
int h[N], nxt[N], to[N], idx;
void addedge(int u, int v) {
to[idx] = v;
nxt[idx] = h[u];
h[u] = idx++;
}
vector<int> ans;
bool mp[N];
bool first = 0;
int dfs(int u) {
if (mp[u]) {
return u;
}
mp[u] = 1;
for (int i = h[u]; ~i; i = nxt[i]) {
int v = to[i];
int t = dfs(v);
if (t) {
return t;
}
}
return 0;
}
void dfs2(int u) {
if (mp[u])
return;
mp[u] = 1;
ans.push_back(u);
for (int i = h[u]; ~i; i = nxt[i]) {
int v = to[i];
dfs2(v);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
memset(h, -1, sizeof h);
cin >> n;
FOR(i, 0, n) {
int t;
cin >> t;
addedge(i + 1, t);
}
FOR(i, 1, n + 1) {
memset(mp, 0, sizeof mp);
int t = dfs(i);
if (t) {
memset(mp, 0, sizeof mp);
dfs2(t);
cout << SZ(ans) << "\n";
FOR(i, 0, SZ(ans)) {
cout << ans[i] << " ";
}
cout << "\n";
return 0;
}
}
return 0;
}
D - Grid Ice Floor
题意
给定一个N*M
的图,图中有两种格子.
和#
,保证最外一层都是#
,现在你位于(2,2)
(从1开始算),保证(2,2)
是.
。
现在开始移动,每次可以选择上下左右4个方向中的一个,方向选定后,除非下一个格子是#
,否则一直沿着当前方向移动。遇到#
后,可以再次移动。
问你最多能走过的多少个.
。
题解
方向的编码
0表示上
1表示右
2表示下
3表示左
这样编码的好处就是对于方向op
,可以通过op ^ 2
来获得与op
相反的方向。
使用vis[i][j][4]
来记录在(i,j)
这个点,上下左右4个方向是否都遍历过。
使用cnt[i][j]
来记录(i,j)
这个点是否遍历过。
由于是一直走一个方向,考虑记录方向op
的dfs。
初始时给(2,2)
这个点一个特殊的方向值来表示它是起点。
对于(2,2)
这个点,4个方向哪个能走就走哪个方向,比如方向op
,则记录vis[2][2][op] = 1;
表示这个方向已经走过了。
对于下一个格子是#
的情况,首先设当前坐标为(x,y)
,当前方向是op
,那么记录我们来的这条路已经走过了,即vis[x][y][op ^ 2] = 1;
,再以这个点向4个方向扩散。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define lowbit(x) ((x) & -(x))
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1 ) | 1)
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
const int N = 2e2 + 10;
int ans = 0;
bool vis[N][N][4];
bool cnt[N][N];
int dx[4] = {-1,0,1,0};
int dy[4] = {0, 1, 0, -1};
void dfs(int x,int y,int op, vector<string>& g) {
if (!cnt[x][y]) {
cnt[x][y] = 1;
ans++;
}
if (op != -1) {
int tx = x + dx[op];
int ty = y + dy[op];
if (g[tx][ty] == '#') {
vis[x][y][op ^ 2] = 1;
FOR (i, 0, 4) {
if (!vis[x][y][i]) {
vis[x][y][i] = 1;
int txx = x + dx[i], tyy = y + dy[i];
if (g[txx][tyy] != '#') {
dfs(txx,tyy,i,g);
}
}
}
} else {
dfs(tx,ty,op,g);
return;
}
} else {
FOR (i, 0, 4) {
if (!vis[x][y][i]) {
vis[x][y][i] = 1;
int tx = x + dx[i], ty = y + dy[i];
if (g[tx][ty] != '#') {
dfs(tx,ty,i,g);
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<string> v(n);
FOR(i, 0, n) cin >> v[i];
dfs(1,1, -1, v);
cout << ans << "\n";
return 0;
}
E - Defect-free Squares
题意
在N*M
的区域内,有k
个洞。
问在这N*M
的区域内,有多少个不同的无洞正方形区域。单独一个不是洞的点也是无洞的正方形区域。
题解
由于要对正方形内的数据进行统计,考虑二维前缀和。
对于一系列无洞正方形的左上角(i,j)
,肯定存在一个值len
,使得由(i,j)
和(i+len,j+len)
组成的正方形是一个无洞正方形,而(i,j)
和(i+len+1,j+len+1)
组成的正方形不是一个无洞正方形,发现具有二分的性质,于是二分寻找以(i,j)
为左上角的正方形最大能有多大,并记录到答案中。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define lowbit(x) ((x) & -(x))
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1 ) | 1)
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
const int N = 2e5 + 10;
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
vector<vector<int>> v(n + 1, vector<int> (m + 1, 0));
ll ans = 0;
FOR (i,0,k) {
int a, b;
cin >> a >> b;
v[a][b] ++;
}
FOR (i, 1,n + 1) {
FOR (j, 1,m + 1) {
v[i][j] += v[i-1][j] + v[i][j-1] - v[i-1][j-1];
}
}
FOR (i,1,n+1) {
FOR (j, 1, m + 1) {
int l = 0, r = min(n,m) ;
while (l < r) {
int mid = l + r >> 1;
int ti = i + mid, tj = j + mid;
if (ti > n || tj > m || v[ti][tj] - v[i-1][tj] - v[ti][j - 1] + v[i-1][j-1] > 0) r = mid;
else l = mid + 1;
}
ans += l;
}
}
cout << ans << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?