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

URL:https://atcoder.jp/contests/abc310

目录

A

Problem/题意 

Thought/思路

Code/代码

B

Problem/题意

Thought/思路

Code/代码

C

Problem/题意

Thought/思路

Code/代码

D

Problem/题意

Thought/思路

Code/代码

E

Problem/题意

Thought/思路

Code/代码


A

Problem/题意 

购买一件物品有两种方法:要么用 P 元,要么用 Q 元并且得多买一样菜 Di。

Thought/思路

模拟。

Code/代码

#include "bits/stdc++.h"

signed main() {
	int n, p, q; std::cin >> n >> p >> q;
	int min = 1e9;
	for (int i = 1; i <= n; ++ i) {
		int x; std::cin >> x;
		min = std::min(x, min);
	}
	std::cout << std::min(min + q, p);
}

B

Problem/题意

有 N 个产品,每个产品的价格是 Pi,每个产品有 Ci 个功能,用 Fij 来表示。

问是否有一对产品满足下面的条件:

Thought/思路

N 较小,暴力每一种组合。Fij 较小,数组标记每一种产品的功能。最后满足三个条件即可。

Code/代码

#include "bits/stdc++.h"

int n, m, price[107],cnt[107];
std::bitset <107> f[107];

bool check(int i, int j) {
	if (price[i] <= price[j]) {
		std::bitset<107> t = f[i] & f[j];
		if (t == f[j] and (price[i] < price[j] or t != f[i])) {
			return true;
		}
	}
	return false;
}

signed main() {
	std::cin >> n >> m;
	for (int i = 1; i <= n; ++ i) {
		std::cin >> price[i] >> cnt[i];
		for (int j = 1; j <= cnt[i]; ++ j) {
			int x; std::cin >> x;
			f[i][x] = 1;
		}
	}

	for (int i = 1; i <= n; ++ i) {
		for (int j = 1; j <= n; ++ j) {
			if (i == j) continue;
			if (check(i, j)) {
				std::cout << "Yes";
				return 0;
			}
		}
	}
	std::cout << "No";
	return 0;
}

C

Problem/题意

对于一个字符串,它的逆序和正序定义为相同的字符串。

给出 N 个字符串,问有几个字符串不同。

Thought/思路

可以用 set 去重,那么关键就在于如何判断插入条件。

Code/代码

#include "bits/stdc++.h"

signed main() {
	int n; std::cin >> n;
	std::set <std::string> st;
	for (int i = 1; i <= n; ++ i) {
		std::string s; std::cin >> s;
		if (!st.count(s)) {
			std::reverse(s.begin(), s.end());
			if (!st.count(s)) {
				st.insert(s);
			}
		}
	}
	std::cout << st.size();
}

D

Problem/题意

用 N 个运动员组建 T 个队伍,但是队员中有 M 对关系是敌对的,不能放在同一个队伍,问有多少种分配方式。

其中,[1,2]、[3] 和 [3]、[1、2] 是同一种方式。

Thought/思路

N、T 都只有 10,所以可以暴搜。但是直接暴搜就会有 N^{T} 的复杂度,所以要剪枝。

我们发现,[1,2]、[3] 和 [3]、[1、2] 是同一种方式,但 [1,3]、[2] 和 [1,2]、[3] 显然不是同一种。所以,我们可以固定分配的顺序,也就是先分配 1 号运动员,然后分配 2 号运动员。

这样就可以在分配的时候,排除掉存在敌对关系的队伍,将其放入没有敌对关系的队伍,同时也能保证前后队伍之间一定是以最小那号运动员的编号来升序排列。

还有最后一个问题,排列组合问题会有回溯,回溯就会将当前递归的运动员弹出某个队伍,也就有可能导致该队伍没有人,即违反了题目要求,此时要 return。

Code/代码

#include "bits/stdc++.h"

int n, t, m, inc[11][11], ans;

std::vector <int> v[11]; // 每个组包含的人

void dfs(int i) { // 第i个人的分组情况
	if (i > n) {
		for (int x = 1; x <= t; ++ x) {
			if (v[x].size() == 0) return;
		}
		ans ++;
		return;
	}
	for (int x = 1; x <= t; ++ x) {
		bool flag = true;
		for (auto &j : v[x]) {
			if (inc[i][j] == 1) flag = false;
		}
		if (flag) {
			v[x].push_back(i);
			dfs(i + 1);
			v[x].pop_back();
		}
		if (!v[x].size()) return;
	} 
}

signed main() {
	std::cin >> n >> t >> m;
	for (int i = 1; i <= m; ++ i) {
		int a, b; std::cin >> a >> b;
		inc[a][b] = inc[b][a] = 1;
	}
	dfs(1);
	std::cout << ans;
}

E

Problem/题意

有如下公式:

f(i,j)\left\{\begin{matrix} A_{i} & (i = j) \\ f(i,j-1) \Lambda A_{j} & (i < j) \end{matrix}\right.

求:

 

其中,\Lambda 是一个位运算,意为:

即有 0 则 1,无 0 则 0。

Thought/思路

5
00110
=========
0 1 0 1 1
  0 1 0 1
    1 0 1
      1 1
        0

7
0000000
=============
0 1 1 1 1 1 1
  0 1 1 1 1 1
    0 1 1 1 1
      0 1 1 1
        0 1 1
          0 1
            0

观察上面两个例子,就很容易发现递推规律:

a[i] = 0:
	dp[i][0] = 1
	dp[i][1] = i - 1
a[i] = 1:
	dp[i][0] = dp[i - 1][1]
	dp[i][1] = dp[i - 1][0] + 1

其中,dp[i][0] 表示当前第 i 个位置有多少个以0结尾的字符串,dp[i][1] 表示当前第 i 个位置有多少个以 1 结尾的字符串。

每次把 dp[i][1] 加起来即可。

Code/代码

#include "bits/stdc++.h"

#define int long long

int a[1000007], n, dp[1000007][2];
char s[1000007];

signed main() {
	std::cin >> n >> s + 1;
	for (int i = 1; i <= n; ++ i) {
		a[i] = s[i] - '0';
	}

	int ans = 0;
	for (int i = 1; i <= n; ++ i) {
		if (a[i] == 0) {
			dp[i][0] = 1;
			dp[i][1] = i - 1;
		} else {
			dp[i][0] = dp[i - 1][1];
			dp[i][1] = dp[i - 1][0] + 1;
		}
		ans += dp[i][1];
	}
	std::cout << ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值