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

Educational Codeforces Round 92 (Rated for Div. 2)

A. LCM Problem

题目大意

给定区间 [ l , r ] [l, r] [l,r],让你找到正整数 x x x y y y满足 l ≤ x < y ≤ r l \leq x < y \leq r lx<yr,并且 l ≤ l c m ( x , y ) ≤ r l \leq lcm(x, y) \leq r llcm(x,y)r

解题思路

根据题意有:
l ≤ l c m ( x , y ) = x × y g c d ( x , y ) ≤ r l \leq lcm(x,y)=\frac{x \times y}{gcd(x,y)} \leq r llcm(x,y)=gcd(x,y)x×yr
l × g c d ( x , y ) x ≤ y ≤ r × g c d ( x , y ) x \frac{l \times gcd(x,y)}{x} \leq y \leq \frac{r \times gcd(x,y)}{x} xl×gcd(x,y)yxr×gcd(x,y)
其中 l ≤ x < y ≤ r l \leq x < y \leq r lx<yr
那么显然当 x = g c d ( x , y ) x=gcd(x,y) x=gcd(x,y) y y y的范围最大,为 [ l , r ] [l,r] [l,r],即 y y y x x x的倍数,则有 y ∣ m i n = 2 x y|_{min}=2x ymin=2x
所以我们令 x = l x=l x=l y = 2 x y=2x y=2x,若 y > r y>r y>r,则无解

时间复杂度 O ( 1 ) O(1) O(1)

AC代码

#include 
using namespace std;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T; 
	cin >> T;
	while (T--) {
		int l, r; 
		cin >> l >> r;
		if (r >= l * 2) cout << l << " " << l * 2 << '\n';
		else cout << "-1 -1\n";
	}
	return 0;
}

B. Array Walk

题目大意

有一个序列 a a a,你初始位置为 1 1 1,你必须移动 k k k次,每次可以向左或向右移动一格,并获得所在位置的分数,要求是你不能连续向左移动,并且向左移动次数不能大于 z z z,问你获得的最大分数为多少

解题思路

首先我们需要明确以下三点:

  1. 假设你目前处于 i i i位置,那么你肯定向右移动了 i − 1 i-1 i1次到达该位置
  2. 每次向左移动之后一定会向右移动一次(因为不能连续向左移动),也就是说假设你向左了 j j j次,那么总消耗次数为 2 j 2j 2j
  3. 根据贪心原则,如果你要向左移动多次,肯定会在 j ∈ [ 1 , i ] j \in [1,i] j[1,i] a [ j ] + a [ j − 1 ] a[j]+a[j-1] a[j]+a[j1]最大的地方来回跑,因为别的地方所获得的分数一定小于这个地方

想清楚以上三点事情就简单了,我们可以枚举终点 i i i,计算其得分的最大值,显然 i ∈ [ k − 2 z − 1 , k + 1 ] i \in [k-2z-1,k+1] i[k2z1,k+1] k − ( i + 1 ) ≥ 2 z k-(i+1) \geq 2z k(i+1)2z

对于终点 i i i,我们向右的基础次数是 i + 1 i+1 i+1,那么向左的次数 z z zz zz则为 k − ( i + 1 ) k-(i+1) k(i+1),若 z z zz zz为偶数,我们就可以选择 j ∈ [ 1 , i ] j \in [1,i] j[1,i] a [ j ] + a [ j − 1 ] a[j]+a[j-1] a[j]+a[j1]最大的地方来回跑,此时 p o i n t = ( max ⁡ j = 1 i ( a j + a j + 1 ) ) × k − ( i + 1 ) 2 + ∑ j = 1 i a i point=(\max_{j=1}^{i}(a_{j}+a_{j+1}))\times \frac{k-(i+1)}{2}+\sum_{j=1}^{i}a_{i} point=(maxj=1i(aj+aj+1))×2k(i+1)+j=1iai,否则若 z z zz zz为奇数,那么我们只能在 i i i i − 1 i-1 i1之间来回跑,最后停在 i − 1 i-1 i1位置,此时 p o i n t = ( a i + a i − 1 ) × k − ( i + 1 ) − 1 2 + a i − 1 + ∑ j = 1 i a i point=(a_{i}+a_{i-1})\times \frac{k-(i+1)-1}{2}+a_{i-1}+\sum_{j=1}^{i}a_{i} point=(ai+ai1)×2k(i+1)1+ai1+j=1iai

max ⁡ j = 1 i \max_{j=1}^{i} maxj=1i ∑ j = 1 i a i \sum_{j=1}^{i}a_{i} j=1iai显然可以预处理,那么时间复杂度为 O ( n ) O(n) O(n)

AC代码

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int a[maxn], b[maxn], sum[maxn];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	register int T; 
	cin >> T;
	while (T--) {
		memset(b, 0, sizeof(b));
		register 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];
		}
		int Max = 2;
		for (int i = 2; i <= n; ++i) {
			if (a[i - 1] + a[i] > a[Max - 1] + a[Max]) {
				b[i] = i - 1;
				Max = i;
			}
			else b[i] = Max - 1;
		}
		int res = 0;
		for (int i = 2; i <= k + 1; ++i) {
			int zz = k - i + 1;
			if (zz > z * 2) continue;
			if ((zz & 1) == 0) {
				res = max(res, (a[b[i]] + a[b[i] + 1]) * (zz / 2) + sum[i]);
			}
			else {
				res = max(res, (a[i] + a[i - 1]) * (zz / 2) + sum[i] + a[i - 1]);
			}
		}
		cout << max(res, sum[k + 1]) << '\n';
	}
	return 0;
}

C. Good String

题目大意

给你一个字符串 s s s,让你从中删去一些字符变成 t t t使得 t n t 1 t 2 . . . t n − 1 = t 2 t 3 . . . t n t 1 t_{n}t_{1}t_{2}...t_{n-1}=t_{2}t_{3}...t_{n}t_{1} tnt1t2...tn1=t2t3...tnt1,问你删去字符的最少数量是多少

解题思路

手动模拟一下
n = 2 n=2 n=2时, t 2 t 1 = t 2 t 1 t_{2}t_{1}=t_{2}t_{1} t2t1=t2t1显然成立
n = 3 n=3 n=3时, t 3 t 1 t 2 = t 2 t 3 t 1 t_{3}t_{1}t_{2}=t_{2}t_{3}t_{1} t3t1t2=t2t3t1需要满足 t 1 = t 2 = t 3 t_{1}=t_{2}=t_{3} t1=t2=t3
n = 4 n=4 n=4时, t 4 t 1 t 2 t 3 = t 2 t 3 t 4 t 1 t_{4}t_{1}t_{2}t_{3}=t_{2}t_{3}t_{4}t_{1} t4t1t2t3=t2t3t4t1需要满足 t 1 = t 3 , t 2 = t 4 t_{1}=t_{3},t_{2}=t_{4} t1=t3t2=t4
n = 5 n=5 n=5时, t 5 t 1 t 2 t 3 t 4 = t 2 t 3 t 4 t 5 t 1 t_{5}t_{1}t_{2}t_{3}t_{4}=t_{2}t_{3}t_{4}t_{5}t_{1} t5t1t2t3t4=t2t3t4t5t1需要满足 t 1 = t 2 = t 3 = t 4 = t 5 t_{1}=t_{2}=t_{3}=t_{4}=t_{5} t1=t2=t3=t4=t5
n = 6 n=6 n=6时, t 6 t 1 t 2 t 3 t 4 t 5 = t 2 t 3 t 4 t 5 t 6 t 1 t_{6}t_{1}t_{2}t_{3}t_{4}t_{5}=t_{2}t_{3}t_{4}t_{5}t_{6}t_{1} t6t1t2t3t4t5=t2t3t4t5t6t1需要满足 t 1 = t 3 = t 5 , t 2 = t 4 = t 6 t_{1}=t_{3}=t_{5},t_{2}=t_{4}=t_{6} t1=t3=t5t2=t4=t6
. . . ... ...
那么规律已经很明显了,我们可以取 s s s中出现最多的字母,或者取两个不同的字母分别放在奇数位和偶数位上,前提是这两个字母在原字符串中需要满足相应的次序关系,由于字母只包含 0 ∼ 9 0 \sim 9 09,我们可以暴力枚举这两个数字,总复杂度为 O ( 100 × n ) O(100\times n) O(100×n)

需要注意的是可保留的字符数最少为 2 2 2

AC代码

#include 
using namespace std;
typedef long long ll;
int num[15];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T; 
	cin >> T;
	while (T--) {
		memset(num, 0, sizeof(num));
		string s;
		cin >> s;
		int len = s.length();
		int Max = 2;
		for (int i = 0; i < len; ++i) {
			int ch = s[i] - '0';
			++num[ch];
			Max = max(Max, num[ch]);
		}
		for (int i = 0; i <= 9; ++i) {
			for (int j = 0; j <= 9; ++j) {
				if (i == j) continue;
				int cnt = 0;
				for (int k = 0; k < len; ++k) {
					int ch = s[k] - '0';
					if ((cnt & 1) == 0 && ch == i) ++cnt;
					else if ((cnt & 1) && ch == j) ++cnt;
				}
				Max = max(Max, (cnt / 2) * 2);
			}
		}
		cout << len - Max << '\n';
	}
	return 0;
}

你可能感兴趣的:(codeforces)