Educational Codeforces Round 92 (Rated for Div. 2)题解

Educational Codeforces Round 92 (Rated for Div. 2)


A. LCM Problem

题意:询问 ([l,r]) 中是否存在 (x,y(x eq y)) 使得 (lleq x, y, LCM(x,y)leq r)

思路(LCM(x,y)) 必定同时是 (x,y) 的倍数,并且 (x eq y) ,因此 (LCM(x,y)) 至少是 (min{{x,y}}) 的两倍。因此直接构造一组最小的 ((x,y))((l,2l))

#include <bits/stdc++.h>
#define db double
using namespace std;
 
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	int t; cin >> t;
	while (t--) {
		long long l, r;
		cin >> l >> r;
		if (l + l > r) cout << "-1 -1
";
		else cout << l << ' ' << l + l << '
';
	}
	return 0;
}

B. Array Walk

题意:你一开始在 (1) 拥有权值 (a_1) ,你可以向左或向右走,走到 (i) 增加权值 (a_i),但是不能连续向左走,比如不能((5,4,3,4,5))但是可以 ((5,4,5,4,5)),问走 (k) 步,最多向左走 (z(leq 5)) 次获得的最大权值是多少。

思路:分成两种情况 一种是中间有 (z) 次向左后立即向右,另一种是 (z-1) 次向左,走到最右端后向左走一步并结束。

每次向左并立即向右,一定是区间内最大的相邻两格的和,预处理一下。枚举 (z) 的值,计算,取最大值即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn];
int v[maxn], sum[maxn];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	int t; cin >> t;
	while (t--) {
		int n, k, z;
		cin >> n >> k >> z;
		for (int i = 1; i <= n; ++i) {
			cin >> a[i];
			sum[i] = sum[i - 1] + a[i];
			v[i] = 0;
		}
		for (int i = 2; i <= n; ++i)
			v[i] = max(v[i - 1], a[i] + a[i - 1]);
		k++;
		int ans = 0;
		for (int i = 0; i <= z; ++i) {
			int cnt = sum[k];
			if (k - 2 * i >= 2) {
				int s1 = sum[k - 2 * i] + i * v[k - 2 * i];
				cnt = max(s1, cnt);
			}
			if (i && k - 2 * i + 1 >= 2) {
				int g = k - 2 * i + 1;
				int s2 = sum[g] + (i - 1) * v[g] + a[g - 1];
				cnt = max(cnt, s2);
			}
			ans = max(ans, cnt);
		}
		cout << ans << '
';
	}
	return 0;
}

C. Good String

题意:给定一个由 (0 ext{~}9) 构成的字符串 (s=t_1t_2cdots t_n) ,询问最少从 (s) 中删除几个字符,使得新得到的字符串满足: (t_2t_3cdots t_{n-1}t_nt_1=t_nt_1t_2cdots t_{n-2}t_{n-1})

思路:我们很容易推出:(t_1=t_3=t_5=cdots cap t_2=t_4=cdots t_n) 。因此,该字符串的构成最多只有两种字符,并且只有两种字符时,必定形如 (121212cdots) 。由于该字符串由 (0 ext{~}9) 构成,这一共只有 (9 imes9+10) 种情况,直接暴力枚举即可。

#include <bits/stdc++.h>
using namespace std;
 
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	int t; cin >> t;
	while (t--) {
		string s; cin >> s;
		vector<vector<int> > pos(10);
		for (int i = 0; i < s.length(); ++i) {
			int x = s[i] - '0';
			pos[x].push_back(i);
		}
		int ans = 0;
		for (int i = 0; i < 10; ++i) ans = max(ans, (int)pos[i].size());
		for (int i = 0; i < 10; ++i) {
			for (int j = 0; j < 10; ++j) {
				if (i == j) continue;
				int cnt = 0;
				int l = 0, r = 0, preR = -1;
				while (l < pos[i].size() && r < pos[j].size()) {
					if (pos[i][l] < pos[j][r] && pos[i][l] > preR) {
						cnt += 2;
						preR = pos[j][r];
						++l, ++r;
					}
					else if (pos[i][l] > pos[j][r]) ++r;
					else ++l;
				}
				ans = max(ans, cnt);
			}
		}
		cout << (int)s.length() - ans << '
';
	}
	return 0;
}

D. Segment Intersections

题意:给出 (n) 条线段 ([l_1,r_1])(n)([l_2,r_2]),每次操作可以将一条线段 ([x,y]) 变成 ([x-1,y])([x,y+1]),问最少几次操作使得每对线段交的总和大于等于 (k)(线段长度为 (y-x))。

思路:将线段交分成三个阶段,令 (l_1 < l_2) 且 两条线段相离,第一阶段为 (r_1) 延伸到 (l_2)(l_2) 延申到 (r_1)(性价比 (2) ),第二阶段为 (r_1)(l_2)(r_2)(l_2)(r_1)(l_1)(性价比 (1) ),第三阶段无限延申(性价比 (2) )。

显然第二阶段最合算,第一、第三阶段相同,那么枚举有几条线段完成第一阶段,然后尽量完成第二阶段,否则第三阶段取最小值即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	int t; cin >> t;
	while (t--) {
		int n, k;
		cin >> n >> k;
		int l1, r1, l2, r2;
		cin >> l1 >> r1 >> l2 >> r2;
		if (l1 > l2) swap(l1, l2), swap(r1, r2);
		int s1 = 0, s2 = 0;
		if (l2 >= r1) s1 = l2 - r1;
		//相交代价

		//相交长度
		int intersect = 0;
		if (l2 <= r1) intersect = min(r1, r2) - l2;
		//1 代价的长度
		s2 = r1 - l1 + r2 - l2 - intersect * 2;

		if (intersect * n >= k) {
			cout << "0
";
			continue;
		}
		if (s1 && k <= s1) {
			cout << s1 + k << '
';
			continue;
		}
		int ans = 1e18;
		for (int i = 1; i <= n; i++) {
			int cnt = 0, now = intersect * n;
			cnt += i * s1 * 2;
			now += i * s1;
			if (now >= k) {
				ans = min(ans, cnt);
				break;
			}
			if (now + i * s2 >= k) {
				cnt += k - now;
				ans = min(ans, cnt);
				continue;
			}
			cnt += i * s2;
			now += i * s2;
			cnt += (k - now) * 2;
			ans = min(ans, cnt);
		}
		cout << ans << '
';
	}
	return 0;
}

E. Calendar Ambiguity

题意( ext{Berland year})(m) 个月构成,每个月有 (d) 天,每星期有 (w) 天。询问有几对 ((x,y)) 满足 (x)(y) 日和 (y)(x) 日对应的星期几相同。

思路:转化题意为 ([(x-1)d+y] \% w = [(y-1)d+x] \% w) ,然后进行推导:

[egin{aligned} &[(x-1)d+y] \% w = [(y-1)d+x] \% w \ Rightarrow &(d-1)(x-y) equiv 0 mod w \&设 g = gcd(d - 1, w),则: \&frac{d-1}{g}(x-y) equiv 0mod{frac{w}{g}} \ Rightarrow &frac{w}{g}|(x-y)end{aligned} ]

因此,(x-y) 必定是 (frac{w}{g}) 的倍数,简单地推一下公式即可。

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	int t; cin >> t;
	while (t--) {
		ll m, d, w;
		cin >> m >> d >> w;
		if (d == 1) {
			cout << "0
";
			continue;
		}
		ll g = __gcd(w, d - 1);
		ll ww = w / g;
		ll top = min(d, m);
		ll num = (ll)floor(1.0 * top / ww);
		ll ans = top * num - num * (num + 1ll) / 2ll * ww;
		cout << ans << '
';
	}
	return 0;
}
原文地址:https://www.cnblogs.com/st1vdy/p/13401579.html