Codeforces Round #821 (Div. 2) A ~ D2

A. Consecutive Sum

题目链接 :

Problem - A - Consecutive Sum

题面 :

在这里插入图片描述

题目大意:

给一个由n个整数组成的数组a,可以进行k次以下操作:
1.选择两个下标i和j,满足i mod k = j mod k
2.交换ai和aj
操作结束后选择k个连续的数,相加的值为获得的分数,找到你可以获得的最大分数。

思路:

总体思路:将要找的数全部放在前k个位置,则计算分数时只需相加前k个数的值。
操作:对于1 <= i <= k,循环相加k,判断a[i] 和 a[i + cnt * k]的大小(cnt的值为循环相加k的次数)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
ll a[1000], b[1000];
void solve() {
	int n, k;
	cin >> n >> k;
	for (int i = 1 ; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= k; i++) {
		int cnt = 1;
		b[i] = a[i];
		while (i + cnt * k <= n) {
			if (b[i] < a[i + cnt * k]) b[i] = a[i + cnt * k];
			cnt++;
		}
	}
	ll ans = 0;
	for (int i = 1; i <= k; i++) {
		ans += b[i]; 
	}
	cout << ans << "\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

B. Rule of League

题目链接:

Problem - B - Rule of League

题面:

在这里插入图片描述

题目大意:

有n个选手参加比赛。
首先,一号选手和二号选手比赛,胜者与三号选手比赛,胜者与四号选手比赛…
对于每个选手,他要么赢了x场比赛,要么赢了y场比赛。
问是否存在一种情况使得上述条件成立。

思路:

对于x和y,显然当x=0并且y=0时,找不到任何一种情况满足条件。
同理,当x≠0并且y≠0时,找不到任何一种情况满足条件,因为一号选手和二号选手必定有一位只能参加一场比赛,所以必有一位赢0场。
综上所述,x和y中必存在一个0。
当(n - 1)%(x + y) ≠0时,也不满足条件。
对于能够满足条件的情况,只需令(n - 1)/(x + y)名选手各赢(x + y)场即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
void solve() {
	int n, x, y;
	cin >> n >> x >> y;
	if ((x != 0 && y != 0) || (x == 0 && y == 0)) {
		cout << -1 << "\n";
		return ;
	}
	if (x == 0) {
		if ((n - 1) % y == 0) {
			int m = (n - 1) / y;
			for (int i = 1; i <= m; i++) {
				for (int j = 1; j <= y; j++) cout << 1 + (i - 1) * y + 1 << ' ';
			}
			cout << "\n";
		}else cout << -1 << "\n";
	}else if (y == 0){
		if ((n - 1) % x == 0) {
			int m = (n - 1) / x;
			for (int i = 1; i <= m; i++) {
				for (int j = 1; j <= x; j++) cout << 1 + (i - 1) * x + 1 << ' ';
			}
			cout << "\n";
		} else cout << -1 << "\n"; 
	} 
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

C.Parity Shuffle Sorting

题目链接:

Problem - C - Parity Shuffle Sorting

题面:

在这里插入图片描述

题目大意:

有一个由n个非负整数组成的数组a,进行以下操作:
1.选择下标l和r
2.当al + ar的值为奇数时,令ar = al,若为偶数,令al = ar
要求使用不超过n次操作,使数组有序且非递减

思路:

令数组内所有数的值都变为a[n]

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int a[MAX];
int check(int a, int b) {
	return (a + b) % 2;
}
void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	if (is_sorted(a + 1, a + 1 + n) || n == 1) {
		cout << 0 << "\n";
		return ;
	}
	vector<pair<int, int>> vc;
	if (check(a[1], a[n])) {
		a[n] = a[1];
		vc.push_back({1, n});
	} 
	for (int i = 1; i < n; i++) {
		if (!check(a[i], a[n]) && a[i] != a[n]) {
			a[i] = a[n];
			vc.push_back({i, n});
		}
	}
	for (int i = 2; i < n; i++) {
		if (check(a[1], a[i])) {
			a[i] = a[1];
			vc.push_back({1, i});
		}
	}
	cout << vc.size() << "\n";
	for (int i = 0; i < vc.size(); i++) {
		cout << vc[i].first << " " << vc[i].second << "\n";
	}
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

D1. Zero-One (Easy Version)

题目链接:

Problem - D1 - Zero-One (Easy Version)

题面:

在这里插入图片描述

题目大意:

给两个01串a, b,对01串a进行如下操作使得a=b
1.选择下标l和r
2.将al的值改为1-al,将ar的值改为1-ar
如果l+1=r,代价为x,反之,代价为y
求最小花费和操作步骤

思路:

记录两个01串不同的位置。
因为每次操作有两个位置的值改变,所以当位置数%2≠0时,不存在操作满足条件。
因为题目限制了x>=y,所以优先变换两个位置差大于1的。
当位置数>2时,全部选择y花费来操作。
当位置数=2时,花费为min(x,2 *y)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int pos[3005];
void solve() {
	int n;
	ll x, y;
	cin >> n >> x >> y;
	string s1, s2;
	cin >> s1 >> s2;
	int cnt = 0;
	for (int i = 0; i < n; i++) {
		if (s1[i] != s2[i]) pos[++cnt] = i;
	}
	if (cnt % 2 != 0) {
		cout << -1 << "\n";
		return ;
	}
	if (cnt == 0) {
		cout << 0 << "\n";
		return ;
	}
	if (cnt == 2 && pos[2] - pos[1] == 1) cout << min(x, y * 2) << "\n";
	else {
		cout << y * cnt / 2 << "\n";
	}
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

D2.Zero-One (Hard Version)

题目链接:

Problem - D2 - Zero-One (Hard Version)

题面:

在这里插入图片描述

题目大意:

与D1大致一样,少了x >= y的限制和数组范围的扩大

思路:

动态规划:
设dp[i][j]表示将a[i,j]变为b[i,j]所需的最小花费

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int n;
string s1, s2;
ll x, y;
ll dp[5005][5005];
vector<int> vc;
int calc(int i, int j) {
	int pos = vc[j] - vc[i];
	if (pos == 1) return min(x, y * 2);
	else return min(x * pos, y);
}
void solve() {
	cin >> n >> x >> y;
	cin >> s1 >> s2;
	vc.clear();
	for (int i = 0; i < n; i++) {
		if (s1[i] != s2[i]) {
			vc.push_back(i);
		}
	}
	int l = vc.size();
	if (l % 2 == 1) {
		cout << -1 << "\n";
		return ;
	}
	for (int k = 2; k <= l; k += 2 ) {
		for (int i = 0; i + k - 1 < l; i ++ ) {
			int j = i + k - 1;
			if (k == 2) dp[i][j] = calc(i, j);
			else
				dp[i][j] = min({dp[i][j - 2] + calc(j - 1, j), dp[i + 1][j - 1] + calc(i, j), dp[i + 2][j] + calc(i, i + 1), y * (j - i + 1) / 2});
		}
	}
	cout << dp[0][l - 1] << "\n";
}
int main() {
	IOS;
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值