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

目录

A

Problem/题意

Thought/思路

Code/代码

B

Problem/题意

Thought/思路

Code/代码

C

Problem/题意

Thought/思路

Code/代码

D

Problem/题意

Thought/思路

Code/代码

E

Problem/题意

Thought/思路

Code/代码


A

Problem/题意

给出连续 n * 7 天的步数,求每周有多少步。

Thought/思路

Code/代码

#include "bits/stdc++.h"

signed main() {
	int n; std::cin >> n;
	int sum = 0;
	for (int i = 1; i <= 7 * n; ++ i) {
		int x; std::cin >> x;
		sum += x;
		if (i % 7 == 0) {
			std::cout << sum << " ";
			sum = 0;
		}
	}
	return 0;
}

B

Problem/题意

给出n个字符串,求两两组合之后,有没有回文串。

Thought/思路

数据很小,暴力

Code/代码


#include "bits/stdc++.h"

bool check(std::string s) {
	bool res = true;
	int len = s.length();
	for (int i = 0; i < len / 2; ++ i) {
		if (s[i] != s[len - i - 1]) {
			res = false;
			break;
		}
	}
	return res;
}

signed main() {
	int n; std::cin >> n;

	std::vector <std::string > v(n + 1);
	for (int i = 1; i <= n; ++ i) {
		std::cin >> v[i];
	}

	bool flag = false;
	for (int i = 1; i <= n; ++ i) {
		for (int j = i + 1; j <= n; ++ j) {
			std::string a = v[i] + v[j], b = v[j] + v[i];
			if (check(a) or check(b)) {
				flag = true;
			}
		}
	}

	if (flag) std::cout << "Yes";
	else std::cout << "No"; 
}

C

Problem/题意

给出三个字符矩阵a、b、x,将a、b摆放到一个空白的矩阵上,求能否用x将a、b带来的所有黑格子覆盖。

Thought/思路

矩阵很小,首先能想到,假设在一个 20 * 20 的矩阵中,改变a、b的起始位置(本质上就是偏移量),然后检查x的每个点:

(1)对于a,是否在a的范围内,a提供在这个点的块,是不是黑色;

(2)对于b,是否在b的范围内,b提供在这个点的块,是不是黑色;

因为a、b还有可能存在位于x之外的黑色块,因此还要计算一下范围内的黑色快是否一致。

(这题真逆天)

Code/代码



#include "bits/stdc++.h"

std::array <int, 3> n, m, num;

std::array <std::vector <std::string>, 3> s;

signed main() {
	for (int i = 0; i <= 2; ++ i) {
		std::cin >> n[i] >> m[i];

		s[i].resize(n[i]);
		for (int j = 0; j < n[i]; ++ j) {
			std::cin >> s[i][j];
			num[i] += std::count(s[i][j].begin(), s[i][j].end(), '#');
		}
	}
 
	auto check = [&](int ax, int ay, int bx, int by) { // 偏移量
		int cnt = 0;
		for (int i = 0; i < n[2]; ++ i) {
			for (int j = 0; j < m[2]; ++ j) {
				int target = (s[2][i][j] == '#');
				int ta = (i >= ax and j >= ay and i < ax + n[0] and j < ay + m[0] and s[0][i - ax][j - ay] == '#');
				int tb = (i >= bx and j >= by and i < bx + n[1] and j < by + m[1] and s[1][i - bx][j - by] == '#');
				cnt += ta + tb;
				if (target != (ta | tb)) {
					return false;
				}
			}
		}
		return (cnt == num[0] + num[1]);
	};

	for (int ax = -10; ax <= 10; ++ ax) 
		for (int ay = -10; ay <= 10; ++ ay) 
			for (int bx = -10; bx <= 10; ++ bx) 
				for (int by = -10; by <= 10; ++ by)
					if (check(ax, ay, bx, by))
					{
						std::cout << "Yes";
						return 0;
					}

	std::cout << "No";
	return 0;
}

D

Problem/题意

给一个包含 '(' 和 ')' 的字符串,可以将匹配括号内的内容全部删去,问最后的字符串长啥样。

Thought/思路

遇到 '(' 就存入栈,遇到 ')' 就标记,最后做个前缀和。

(这不比C题简单)

Code/代码


#include "bits/stdc++.h"

int l_stk[200007], pre[200007];
int l_top, n;

char s[200007];

signed main() {
	std::cin >> n >> s + 1;

	for (int i = 1; i <= n; ++ i) {
		if (s[i] == '(') l_stk[++ l_top] = i;
		if (s[i] == ')' and l_top > 0) {
			pre[l_stk[l_top --]] ++;
			pre[i + 1] --;
		}
	}

	for (int i = 1; i <= n; ++ i) {
		pre[i] = pre[i] + pre[i - 1];
	}

	for (int i = 1; i <= n; ++ i) {
		if (pre[i] == 0) std::cout << s[i];
	}

}

E

Problem/题意

有n个人排成一个环,有m个不同的数字[0, m - 1],问有多少种分配方案使得相邻两个人的数字不同。

Thought/思路

如果是线性的,那么第一个人是m种,往后都是m - 1种,则有m * (m - 1)^{n - 1}种。

由于要求成环形,那么起到决定作用的就是最后一个数字。

而为了确定最后一个数字,我们需要确定倒数第二个数字的情况:

(1)如果第一个数字和倒数第二个数字相同,答案就是 m * (m - 1)^{n - 1}

(2)如果第一个数字和倒数第二个数字不同,答案就是 m * (m - 1)^{n - 2} * (m - 2)

基于此,我们可以考虑用dp来解决这道题。

dp[i][0/1]表示前 i 个人中,第 1 个数字与第 i 个数字是否一致:

(1)若第1个数字和第i个数字相同,那么 dp[i + 1][0] += dp[i][0] * (m - 2)

(2)若第1个数字和第i个数字不同,那么 dp[i + 1][0] += dp[i][1] * (m - 1)

(3)若新加入了一个数字,且与第1个数字相同,那么 dp[i + 1][1] += dp[i][0] * 1

最后输出 dp[n][0] 即可。

Code/代码


#include "bits/stdc++.h"

#define int long long

int n, m, dp[1000007][2]; // 0:dif 1:same

const int mod = 998244353;

signed main() {
	std::cin >> n >> m;

	dp[1][1] = m; // 一开始只有相同的情况,且为m种
	for (int i = 1; i <= n - 1; ++ i) {
		dp[i + 1][0] += dp[i][0] * (m - 2); // 从 1 与 i 不同的情况转移(所以是dp[i][0]),且与 1 和 i 都不同(所以是dp[i+1][0])
		dp[i + 1][0] += dp[i][1] * (m - 1); // 从 1 与 i 相同的情况转移(所以是dp[i][1]),且与 1 和 i 都不同(所以是dp[i+1][0])

		dp[i + 1][1] += dp[i][0] * 1;

		dp[i + 1][0] %= mod;
		dp[i + 1][1] %= mod;
	}

	std::cout << dp[n][0];

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值