Codeforces Round (2021-04-29)

Published 2021-04-28 16:00 1133 words 6 min read Handwritten Every word here was typed by me.

Zhiheng Wang avatar

Zhiheng Wang

技术文章、个人随笔、项目与作品体验记录

This post is not yet available in English. Showing the original.
Educational Codeforces Round 108 (Rated for Div. 2) A. Red and Blue Beans 题目链接 有 $r$ 个红豆和 $b$ 个蓝豆,要全部分进若干袋。每袋至少各有一个,两种豆子的数量差不能超过 $d$,问能不能分。 先让 $r\le b$。红豆每袋至少放一个,所以最多分 $r$ 袋;每袋最多多放 $d$ 个蓝豆,总共就要求...

Educational Codeforces Round 108 (Rated for Div. 2)

A. Red and Blue Beans

题目链接

题意

有 rr 个红豆和 bb 个蓝豆,要全部分进若干袋。每袋至少各有一个,两种豆子的数量差不能超过 dd,问能不能分。

思路

先让 r≤br\le b。红豆每袋至少放一个,所以最多分 rr 袋;每袋最多多放 dd 个蓝豆,总共就要求 b−r≤drb-r\le dr,也就是 b≤(d+1)rb\le(d+1)r。

满足时把红豆一个一袋,再把蓝豆分进去就够了。乘法用 long long。

代码

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

int main() {
	int t;
	cin >> t;
	while(t--) {
		int r, b, d;
		cin >> r >> b >> d;
		if(r > b) swap(r, b);
		if(r <= b &&  1ll * b <= 1ll * (1 + d) * r) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

B. The Cake Is a Lie

题目链接

题意

从网格的 (1,1)(1,1) 走到 (n,m)(n,m),只能向右或向下。向右一步花当前行号的钱,向下一步花当前列号的钱,问能不能恰好花 kk。

思路

看一下当前位置的行列乘积 xyxy:向右一步增加 xx,向下一步增加 yy,刚好都是这一步的花费。

所以不管怎么走,总花费都是 nm−1nm-1,直接和 kk 比较就行。

代码

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

int main() {
	int t;
	cin >> t;
	while(t--) {
		int n, m, k;
		cin >> n >> m >> k;
		if(k == n * m - 1) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

C. Berland Regional

题目链接

题意

每个学生属于一所大学,有各自的能力值。队伍人数固定为 kk 时,每所大学从强到弱每 kk 人组一队,不够一队的留下。求 k=1…nk=1\ldots n 时,所有参赛学生能力值的总和。

思路

先按大学分组,每组能力值从大到小排,再做前缀和。一所大学有 tt 人,队伍人数是 kk 时,能用上的就是最强的 ⌊t/k⌋k\lfloor t/k\rfloor k 人,查一次前缀和加到答案里。

每组只枚举 k=1…tk=1\ldots t,所有组的大小加起来就是 nn,所以这部分一共只扫 nn 次。时间主要在排序,是 O(nlog⁡n)O(n\log n),总和用 long long。

代码

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

typedef long long ll;
const int maxn = 2e5 + 17;
int n, u[maxn];
vector<ll> v[maxn];
ll s[maxn];
int sz[maxn];

bool cmp(ll a, ll b) {
	return a > b;
}

int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		for(int i = 1; i <= n; i++) {
			s[i] = 0;
			v[i].clear();
			sz[i] = 0;
		}
		for(int i = 1; i <= n; i++) scanf("%d", &u[i]);
		for(int i = 1; i <= n; i++) {
			int tmp; scanf("%d", &tmp);
			v[u[i]].push_back(1ll * tmp);
			sz[u[i]]++;
		}
		for(int i = 1; i <= n; i++) {
			int t = sz[i];
			sort(v[i].begin(), v[i].end(), cmp);
			// for(int j = 0; j < t; j++) printf("%d%c", v[i][j], " \n"[j == t - 1]);
			for(int j = 1; j < t; j++) v[i][j] = v[i][j] + v[i][j - 1];
			for(int j = 1; j <= t; j++) {
				s[j] += v[i][t / j * j - 1];
			}
		}
		for(int i = 1; i <= n; i++) printf("%lld%c", s[i], " \n"[i == n]);
	}
	return 0;
}

D. Maximum Sum of Products

题目链接

题意

给两个长度为 nn 的数组 a,ba,b,最多翻转 aa 的一个连续区间。问 ∑aibi\sum a_i b_i 最大能是多少。

思路

f[l][r] 记翻转 [l,r][l,r] 以后的整个点积。已经知道翻转内层 [l+1,r−1][l+1,r-1] 的结果,再减掉两端原来的贡献,换成交换后的贡献就行:

f[l][r]=f[l+1][r−1]−albl−arbr+albr+arbl.f[l][r]=f[l+1][r-1]-a_lb_l-a_rb_r+a_lb_r+a_rb_l.

长度 1 就是不变,长度 2 单独算,再按区间长度递推。答案先取原来的总和,这样也包含不翻转的情况。时间和空间都是 O(n2)O(n^2)。

代码

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

typedef long long ll;
const int maxn = 5e3 + 17;
int n;
ll a[maxn], b[maxn], f[maxn][maxn], ans;

bool cmp(ll a, ll b) {
	return a > b;
}

int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++) cin >> b[i];
	for(int i = 1; i <= n; i++) f[1][1] += a[i] * b[i];
	for(int i = 2; i <= n; i++) f[i][i] = f[1][1];
	ans = f[1][1];
	// cout << ans << endl;
	for(int l = 1; l < n; l++) {
		int r = l + 1;
		f[l][r] = f[1][1] - a[l] * b[l] - a[r] * b[r] + a[l] * b[r] + a[r] * b[l];
		ans = max(ans, f[l][r]);
	}
	for(int i = 3; i <= n; i++) {
		for(int l = 1; l + i - 1 <= n; l++) {
			int r = l + i - 1;
			f[l][r] = f[l + 1][r - 1] - a[l] * b[l] - a[r] * b[r] + a[l] * b[r] + a[r] * b[l];
			ans = max(ans, f[l][r]);
		}
	}
	// cout << f[3][5] << endl;
	cout << ans << endl;
	return 0;
}

Written by Handwritten

Random Posts

© 2026 Zhiheng Wang @traceonsnow
Powered by theme astro-koharu · Inspired by Shoka
Loading...