URL:https://atcoder.jp/contests/abc311/tasks
目录
A
Problem/题意
给一个只由字符A、B、C组成的字符串,求当A、B、C都至少出现一次的时候,长度为多少。
Thought/思路
模拟
Code/代码
#include "bits/stdc++.h"
int vis[5], ans;
signed main() {
int n; std::cin >> n;
std::string s; std::cin >> s;
for (int i = 0; i < s.length(); ++ i) {
if (s[i] == 'A') vis[0] = 1;
if (s[i] == 'B') vis[1] = 1;
if (s[i] == 'C') vis[2] = 1;
int cnt = 0;
for (int j = 0; j < 3; ++ j) {
if (vis[j] == 1) cnt ++;
}
if (cnt == 3) {
ans = i + 1;
break;
}
}
std::cout << ans;
}
B
Problem/题意
给出n个长度为d的字符串,每个字符串由o和x组成,o代表free,x代表busy。问这n个人共同的free长度最大是多少。
Thought/思路
考虑每一个纵列,若该列上所有字符都为o,则令标记数组tag[i]为1。
最后维护最长连续段即可。
Code/代码
#include "bits/stdc++.h"
int n, d;
char mp[107][107];
signed main() {
std::cin >> n >> d;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= d; ++ j) {
std::cin >> mp[i][j];
}
}
std::vector <int> is(d + 1, 1);
for (int j = 1; j <= d; ++ j) {
for (int i = 1; i <= n; ++ i) {
if (mp[i][j] == 'x') is[j] = 0;
}
}
int ans = 0, cnt = 0;
for (int i = 1; i <= d; ++ i) {
if (is[i] == 0) {
cnt = 0;
} else {
cnt ++;
}
ans = std::max(ans, cnt);
}
std::cout << ans;
}
C
Problem/题意
给出一个简单有向有环图,输出任意一个简单环。
Thought/思路
Tarjan缩点,任取一个强连通分量输出即可。
Code/代码
#include <bits/stdc++.h>
#define int long long
int n;
int tim = 0, top = 0, dfn[200007], low[200007], stk[200007], vis[200007], scc[200007];
std::vector <int> g[200007];
void tarjan(int s) {
low[s] = dfn[s] = ++tim;
stk[++top] = s;
vis[s] = 1;
for (auto& i : g[s]) {
if (dfn[i] == 0) { //没有访问过
tarjan(i);
low[s] = std::min(low[s], low[i]); //回溯
}
else if (vis[i] == 1) {
low[s] = std::min(low[s], low[i]); //回溯
}
}
if (dfn[s] == low[s]) {
while (1) {
int t = stk[top--];
scc[t] = s;
vis[t] = 0;
if (s == t) break;
}
}
}
std::vector <int> lis;
int check[200007], ans;
void dfs(int s) {
if (check[s] == 1) return;
lis.push_back(s);
check[s] = 1;
for (auto &next : g[s]) {
dfs(next);
}
}
signed main() {
std::cin >> n;
for (int i = 1; i <= n; ++i) {
int x; std::cin >> x;
g[i].push_back(x);
}
for (int i = 1; i <= n; ++i) {
if (dfn[i] == 0) tarjan(i);
}
int ans = 0;
for (int i = 1; i <= n; ++ i) {
if (scc[i] != i) {
dfs(i);
break;
}
}
std::cout << lis.size() << "\n";
for (auto &i : lis) std::cout << i << " ";
return 0;
}
D
Problem/题意
'.'代表可行走,'#'代表不可行走,起始位置为(2,2),每次可以选择一个方向,沿着这个方向行走,知道碰到墙,问最多能走过多少个'.'。
Thought/思路
简单的bfs。(说着简单,调了好久)
遍历四个方向,出发前检测一次,沿着一个方向走,每走一步又检测一次,若下一步会撞墙,则结束行走。
细节在于撞墙时点的入队和最后数量的统计。
Code/代码
#include "bits/stdc++.h"
#define int long long
int n, m, ans, vis[207][207];
char mp[207][207];
const int dx[5] = {0, 1, 0, -1, 0};
bool check(int x, int y) {
if (mp[x][y] != '#') return true;
else return false;
}
void bfs() {
std::queue <std::pair <int, int>> q;
q.push({2, 2});
vis[2][2] = 1; // 这个别漏了
while (!q.empty()) {
auto top = q.front(); q.pop();
int tx = top.first, ty = top.second;
for (int i = 0; i <= 3; ++ i) {
int x = tx, y = ty;
if (check(x + dx[i], y + dx[i + 1])) {
while (true) {
int nx = x + dx[i], ny = y + dx[i + 1];
if(check(nx, ny)) {
x = nx, y = ny;
vis[x][y] ++;
} else {
if (vis[x][y] <= 1) q.push({x, y});
break;
}
}
}
}
}
}
signed main() {
std::cin >> n >> m;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
std::cin >> mp[i][j];
}
}
bfs();
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
if (vis[i][j] >= 1) ans ++;
}
}
std::cout << ans;
}
E
Probelm/题意
给定一个矩阵的大小h*w。
对一个以(i,j)为左上角的正方形(边长为n)来说,若它内部没有“hole”,则它是一个holeless square。
另外给出N个hole的位置,问这个h*w的矩阵有多少个holeless square。
Thought/思路
我们发现一个holeless square是一个三元组(i,j,n),它是以(i,j)为左上角的一个正方形。这样的话,我们就可以通过确定n的大小,来判断有多少个正方形中有hole。
这里有两个问题:
1.如何确定n:可以发现,当随着n的不断增大,覆盖到的hole的数量一定是非严格递增的,所以当能覆盖到第一个hole的时候,这个n就是我们要的答案,也就是说,可以通过二分求出这个n;
2.如何判断有hole:二维前缀和。
Code/代码
#include "bits/stdc++.h"
#define int long long
int h, w, N, pre[3007][3007];
struct node {
int x, y;
}v[100007];
bool check(int x, int y, int n) {
if (x + n - 1 > h or y + n - 1 > w) return false;
int num = pre[x + n - 1][y + n - 1] - pre[x - 1][y + n - 1] - pre[x + n - 1][y - 1] + pre[x - 1][y - 1];
if (num == 0) return true;
else return false;
}
signed main() {
std::cin >> h >> w >> N;
for (int i = 1; i <= N; ++ i) {
std::cin >> v[i].x >> v[i].y;
pre[v[i].x][v[i].y] = 1;
}
for (int i = 1; i <= h; ++ i) {
for (int j = 1; j <= w; ++ j) {
pre[i][j] += pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1];
}
}
int ans = 0;
for (int i = 1; i <= h; ++ i) {
for (int j = 1; j <= w; ++ j) {
int l = 0, r = std::max(h, w) + 10;
while (l + 1 != r) {
int mid = (l + r) / 2;
if (check(i, j, mid)) l = mid;
else r = mid;
}
ans += l;
}
}
std::cout << ans;
}