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

Educational Codeforces Round 92 (Rated for Div. 2)


A. LCM Problem

題意:詢問 \([l,r]\) 中是否存在 \(x,y(x\neq y)\) 使得 \(l\leq x, y, LCM(x,y)\leq r\)ios

思路\(LCM(x,y)\) 一定同時是 \(x,y\) 的倍數,而且 \(x\neq y\) ,所以 \(LCM(x,y)\) 至少是 \(\min{\{x,y\}}\) 的兩倍。所以直接構造一組最小的 \((x,y)\)\((l,2l)\)c++

#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\n";
		else cout << l << ' ' << l + l << '\n';
	}
	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)\) 次得到的最大權值是多少。ui

思路:分紅兩種狀況 一種是中間有 \(z\) 次向左後當即向右,另外一種是 \(z-1\) 次向左,走到最右端後向左走一步並結束。spa

每次向左並當即向右,必定是區間內最大的相鄰兩格的和,預處理一下。枚舉 \(z\) 的值,計算,取最大值便可。code

#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 << '\n';
	}
	return 0;
}

C. Good String

題意:給定一個由 \(0\text{~}9\) 構成的字符串 \(s=t_1t_2\cdots t_n\) ,詢問最少從 \(s\) 中刪除幾個字符,使得新獲得的字符串知足: \(t_2t_3\cdots t_{n-1}t_nt_1=t_nt_1t_2\cdots t_{n-2}t_{n-1}\)ci

思路:咱們很容易推出:\(t_1=t_3=t_5=\cdots \cap t_2=t_4=\cdots t_n\) 。所以,該字符串的構成最多隻有兩種字符,而且只有兩種字符時,一定形如 \(121212\cdots\) 。因爲該字符串由 \(0\text{~}9\) 構成,這一共只有 \(9\times9+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 << '\n';
	}
	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\))。string

思路:將線段交分紅三個階段,令 \(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\) )。it

顯然第二階段最合算,第1、第三階段相同,那麼枚舉有幾條線段完成第一階段,而後儘可能完成第二階段,不然第三階段取最小值便可。io

#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\n";
			continue;
		}
		if (s1 && k <= s1) {
			cout << s1 + k << '\n';
			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 << '\n';
	}
	return 0;
}

E. Calendar Ambiguity

題意\(\text{Berland year}\)\(m\) 個月構成,每月有 \(d\) 天,每星期有 \(w\) 天。詢問有幾對 \((x,y)\) 知足 \(x\)\(y\) 日和 \(y\)\(x\) 日對應的星期幾相同。

思路:轉化題意爲 \([(x-1)d+y] \% w = [(y-1)d+x] \% w\) ,而後進行推導:

\[\begin{aligned}\ &[(x-1)d+y] \% w = [(y-1)d+x] \% w \\\ \Rightarrow &(d-1)(x-y) \equiv 0 \bmod w \\&設 g = \gcd(d - 1, w),則: \\&\frac{d-1}{g}(x-y) \equiv 0\bmod{\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\n";
			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 << '\n';
	}
	return 0;
}
相關文章
相關標籤/搜索