[补题记录] Atcoder Beginner Contest 311(A~E)

文章展示了五道编程竞赛题目,涉及字符串中特定字符出现的最短长度、矩阵中共同的free长度、有向图的简单环寻找、二维矩阵的可达范围以及无洞正方形计数问题。解题思路包括模拟、动态规划和图论算法,如二分查找和前缀和的应用。
摘要由CSDN通过智能技术生成

URL:https://atcoder.jp/contests/abc311/tasks

目录

A

Problem/题意

Thought/思路

Code/代码

B

Problem/题意

Thought/思路

Code/代码

C

Problem/题意

Thought/思路

Code/代码

D

Problem/题意

Thought/思路

Code/代码

E

Probelm/题意

Thought/思路

Code/代码


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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值