Codeforces Round #621 (Div. 1 + Div. 2) 解题报告

Codeforces Round #621 (Div. 1 + Div. 2)

【A.Cow and Haybales】

【题目大意】
有一个长为n的序列,每次你可以选择一个位置使其减去1并使其其中一个相邻的位置加上1,问你d次内序列首项的最大值是多少

【解题思路】
显然将posi上的数移动一个到首项上所花的次数为posi,贪心能移就移,那么O(n)模拟就好了

【AC代码】

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--) {
		int n, d, day = 0, sum = 0;
		cin >> n >> d >> sum;
		for (int i = 1; i < n; ++i) {
			int x;
			cin >> x;
			int add = x * i;
			if (day + add <= d) {
				sum += x;
				day += add;
			}
			else {
				sum += (d - day) / i;
				day = d;
			}
		}
		cout << sum << endl;
	}
	return 0;
}

【B.Cow and Friend】

【题目大意】
从(0, 0)出发,每次你可以跳跃一次到距离该位置ak的位置,问最少跳跃几次到达(x, 0)

【解题思路】
有两种跳法,如果是直线跳跃,那么跳跃一次到x轴上,否则斜着跳,可以考虑三角形两边之和大于第三边,如果x大于a序列中的最大值的两倍,那么先跳直线,直到距离小于等于最大值的两倍,否则可能可以跳跃1次到达x或者跳跃2次到达x

【AC代码】

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--) {
		int n, x;
		cin >> n >> x;
		int Max = 0;
		bool flag = false;
		for (int i = 1; i <= n; ++i) {
			int y;
			cin >> y;
			if (x == y) {
				flag = true;
			}
			Max = max(Max, y);
		}
		if (flag) {
			cout << 1 << endl;
			continue;
		}
		if (x % Max == 0) {
			cout << max(x / Max, 1) << endl;
			continue;
		}
		int ans = x / Max + 1;
		cout << max(ans, 2) << endl;
	}
	return 0;
}

【C.Cow and Message】

【题目大意】
给定一个字符串,问你其子序列中出现次数最多的次数

【解题思路】
考虑出现次数最多的子序列长度不会大于2,假设其长度为3,如abc,那么num(ab) >= num(abc),那么dp[i][j]表示每一位字符i的上一位为j出现的次数,cnt[j]表示该位之前字符j出现的次数,那么dp[i][j] = dp[i][j] + cnt[j]

ans = max(ans, dp[i][j], cnt[j])

【AC代码】

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
ll dp[26][26];
ll cnt[26];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	string s;
	cin >> s;
	int l = s.length();
	for (int i = 0; i < l; ++i) {
		int ch = s[i] - 'a';
		for (int j = 0; j < 26; ++j) {
			dp[ch][j] += cnt[j];
		}
		++cnt[ch];
	}
	ll ans = 0;
	for (int i = 0; i < 26; ++i) {
		for (int j = 0; j < 26; ++j) {
			ans = max(ans, dp[i][j]);
		}
	}
	for (int i = 0; i < 26; ++i) ans = max(ans, cnt[i]);
	cout << ans << endl;
	return 0;
}

【D.Cow and Fields】

【题目大意】
给定一个无向图,你需要在k个节点中选择两个点连上一条边,问你最短路的最大值是多少

【解题思路】
假设你选择x和y连上一条边,那么该路径长度为min(dis1[x] + 1 + disn[y], dis1[y] + 1 + disn[x]),假设dis1[x] + 1 + disn[y] < dis1[y] + 1 + disn[x],移项得到dis1[x] - disn[x] < dis1[y] - disn[y],根据这个式子对k个节点排序就可以保证路径上不会经过重复节点,然后我们可以枚举y = a[i],ans = max(ans, tmp + 1 + disn[a[i]]),其中tmp为i之前距离1的最大值

dis数组可以通过bfs得到

【AC代码】

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 2e5 + 10;
int a[maxn];
int dis1[maxn];
int disn[maxn];
bool vis[maxn];
vector<int> G[maxn];
inline bool cmp(int x, int y) {
	return dis1[x] - disn[x] < dis1[y] - disn[y];
}
inline void bfs(int s, int dis[]) {
	queue<int> que;
	que.push(s);
	dis[s] = 0;
	memset(vis, false, sizeof(vis));
	vis[s] = true;
	while (!que.empty()) {
		int u = que.front();
		que.pop();
		for (auto v : G[u]) {
			if (!vis[v]) {
				dis[v] = dis[u] + 1;
				que.push(v);
				vis[v] = true;
			}
		}
	}
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n, m, k;
	cin >> n >> m >> k;
	for (int i = 1; i <= k; ++i) cin >> a[i];
	for (int i = 1; i <= m; ++i) {
		int u, v;
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	bfs(1, dis1);
	bfs(n, disn);
	sort(a + 1, a + k + 1, cmp);
	int ans = 0, tmp = dis1[a[1]];
	for (int i = 2; i <= k; ++i) {
		ans = max(ans, tmp + 1 + disn[a[i]]);
		tmp = max(tmp, dis1[a[i]]);
	}
	cout << min(ans, dis1[n]) << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值