Atcoder Beginner Contest 324题解 A~F abc324

Japan Registry Services (JPRS) Programming Contest 2023 (AtCoder Beginner Contest 324)

A - Same

这类题目我习惯上将整个数组排序,然后判断首尾元素是否相同。

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;

	std::vector<int> a(n);
	for (int i = 0; i < n; i++) {
		std::cin >> a[i];
	}

	std::sort(a.begin(), a.end());

	if (a.front() == a.back()) {
		std::cout << "Yes\n";
	} else {
		std::cout << "No\n";
	}
	return 0;
}
B - 3-smooth Numbers

实际上就是判断 N N N的质因子是否仅包含2和3,那么我们只需要将 N N N不断除以2和3就好了,最终得到1说明符合题意,否则不符合。

注意千万不要去枚举质数,那样会很慢并且没有意义。

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	i64 n;
	std::cin >> n;

	while (n % 2 == 0) {
		n /= 2;
	}

	while (n % 3 == 0) {
		n /= 3;
	}

	std::cout << (n == 1 ? "Yes\n" : "No\n");
	
	return 0;
}
C - Error Correction

若两串仅有一个字符不同,实际上就仅有三个位置:头、尾、中间。

考虑每个 S i S_i Si字符串和 t t t串的最长公共前缀 l c p lcp lcp和最长公共后缀 l c s lcs lcs,若两串相等,则 l c p = = l c s = = t . s i z e ( ) lcp == lcs == t.size() lcp==lcs==t.size();若 S i S_i Si少一个字符, l c p + l c s ≥ t . s i z e ( ) − 1 lcp+lcs \ge t.size() - 1 lcp+lcst.size()1;若 S i S_i Si多一个字符, l c p + l c s ≥ t . s i z e ( ) lcp+lcs \ge t.size() lcp+lcst.size();若 S i S_{i} Si t t t有一个字符不同,则 l c p + l c s ≥ t . s i z e ( ) − 1 lcp+lcs \ge t.size() - 1 lcp+lcst.size()1。合并一下上述情况其实我们可以写出下面的式子:((s.size() == t.size() && lcp + lcs >= s.size() - 1) || (s.size() == t.size() - 1 && lcp + lcs >= s.size()) || (s.size() - 1 == t.size() && lcp + lcs >= t.size()),符合这个条件即能给答案贡献1。

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;
	std::string t;
	std::cin >> t;

	std::vector<int> ans;
	for (int i = 0; i < n; i++) {
		std::string s;
		std::cin >> s;

		int lcp = 0, lcs = 0;
		while (lcp < s.size() && lcp < t.size() && s[lcp] == t[lcp]) {
			lcp++;
		}
		while (lcp < s.size() && lcp < t.size() && s[s.size() - 1 - lcs] == t[t.size() - 1 - lcs]) {
			lcs++;
		}

		if ((s.size() == t.size() && lcp + lcs >= s.size() - 1) || (s.size() == t.size() - 1 && lcp + lcs >= s.size())
			|| (s.size() - 1 == t.size() && lcp + lcs >= t.size())) {
			ans.push_back(i + 1);
		}
	}

	std::cout << ans.size() << "\n";
	for (auto x : ans) {
		std::cout << x << " ";
	}
	
	return 0;
}
D - Square Permutation

由于字符串长度至多为13,那么 N N N最大也就是 1 0 13 10^{13} 1013,我们只需要枚举 0 → 1 0 13 0 \to \sqrt{10^{13}} 01013 ,这些数的平方就好了,枚举每个数的时候考虑原串 S S S中的字符数目是否够用,不够就说明当前枚举的数不符合条件,否则符合条件,贡献+1。

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 3170000;
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;

	std::string s;
	std::cin >> s;

	std::vector<int> cnt(10);
	for (auto c : s) {
		cnt[c - '0']++;
	}

	int ans = 0;
	for (int i = 0; i < N; i++) {
		auto backup = cnt;
		i64 v = 1LL * i * i;
		std::string t = std::to_string(v);
		if (t.size() > n) {
			break;
		}
		t = std::string(n - t.size(), '0') + t;

		bool tag = true;
		for (int j = 0; j < n; j++) {
			if (backup[t[j] - '0'] == 0) {
				tag = false;
			}
			backup[t[j] - '0']--;
		}

		ans += tag;
	}

	std::cout << ans << "\n";
	return 0;
}
E - Joint Two Strings

两个串拼起来包含一个子串,其实就是前面的串包含这个子串的一部分,后面的串包含这个子串的另一部分。那么我们仍然可以从前缀和后缀的角度来考虑,若前串和后串对于子串的前缀和后缀的包含情况的加和大于等于这个子串的话说明这两个串拼接起来之后包含这个字串。后面统计方案数可以双指针也可以二分。

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n;
	std::cin >> n;
	std::string t;
	std::cin >> t;

	std::vector<int> pre(n), suf(n);
	for (int i = 0; i < n; i++) {
		std::string s;
		std::cin >> s;

		int len = 0;
		for (auto c : s) {
			if (c == t[len]) {
				len++;
			}
		}
		pre[i] = len;

		len = 0;
		for (auto c : std::ranges::views::reverse(s)) {
			if (c == t[t.size() - 1 - len]) {
				len++;
			}
		}
		suf[i] = len;
	}

	std::sort(pre.begin(), pre.end());
	std::sort(suf.begin(), suf.end());

	// for (int i = 0; i < n; i++) {
	// 	std::cout << pre[i] << " " << suf[i] << "\n";
	// }
	i64 ans = 0;
	for (auto x : pre) {
		auto p = std::lower_bound(suf.begin(), suf.end(), t.size() - x);
		ans += suf.end() - p;
	}

	std::cout << ans << "\n";
	return 0;
}
F - Beautiful Path

诡异的分数问题求值可以考虑二分。

我们考察本题的式子:题目要求 ∑ b ∑ c \frac{\sum{b}}{\sum{c}} cb最大,我们设 ∑ b ∑ c ≥ t \frac{\sum{b}}{\sum{c}} \ge t cbt,若这个式子合法,那么有 ∑ b ≥ t × ∑ c \sum{b} \ge t \times \sum{c} bt×c,等价于 ∑ t c − ∑ b ≤ 0 \sum{tc} - \sum{b} \le 0 tcb0,也即 ∑ ( t c − b ) ≤ 0 \sum{(tc-b)} \le 0 (tcb)0,因此实际上当前图上每一条边权就是 t c − b tc-b tcb,如果满足条件说明可以以此作为答案下限,否则作为答案上限。

如何求这个式子的最小值呢?由于题目保证边是由较小点连向较大点,所以我们可以直接在有向无环图上DP,求出 ∑ ( t c − b ) ≤ 0 \sum{(tc-b)} \le 0 (tcb)0的最小值判断其作为上限还是下限即可。

#include <bits/stdc++.h>

using i64 = long long;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n, m;
	std::cin >> n >> m;

	std::vector<std::vector<std::array<int, 3>>> adj(n);
	for (int i = 0; i < m; i++) {
		int u, v, b, c;
		std::cin >> u >> v >> b >> c;
		u--, v--;
		adj[u].push_back({v, b, c});
	}

	double lo = 0, hi = 1E9;
	for (int t = 0; t <= 100; t++) {
		double x = (lo + hi) / 2;

		std::vector<double> dp(n, INFINITY);
		dp[0] = .0;
		for (int i = 0; i < n; i++) {
			for (auto [j, b, c] : adj[i]) {
				dp[j] = std::min(dp[j], dp[i] + x * c - b);
			}
		}
		// for (int i = 0; i < n; i++) {
		// 	std::cout << dp[i] << " \n"[i == n - 1];
		// }
		if (dp.back() <= 0) {
			lo = x;
		} else {
			hi = x;
		}
	}

	std::cout << std::fixed << std::setprecision(12);
	std::cout << lo << "\n";
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值