CF1832D1 & CF1832D2 Red-Blue Operations

D1

分情况讨论。

  • k ≤ n k\le n kn 时,

    我们容易想到给一个位置不断地更新,但是这样明显不是最优解,那么,我们可以利用题目所给的每一个的初始红色。

    先把数组从小到大进行排序,再从前往后依次给 a i a_i ai 加上 k , k − 1 … 2 , 1 k,k-1\ldots 2,1 k,k12,1,最后扫一遍求出最大值,时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

  • k > n k>n k>n 时,

    先消耗 n n n 次操作,对其按照 k ≤ n k\le n kn 的做法更新,此时所有位置都是蓝色的。
    我们对每个数做偶数次操作,每两次操作 + 1 +1 +1,最后可能剩下一个操作(减),我们把它丢给最大的,再计算最大值。

时间复杂度为 O ( n log ⁡ n + n q ) O(n\log n+nq) O(nlogn+nq)

代码:

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int maxn = 1e4 + 10;

int n, q;
int a[maxn];

signed main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> q;
	for (int i = 1; i <= n; ++i) cin >> a[i];
	sort(a + 1, a + n + 1);
	while (q--) {
		int s = 0, x, ans = 1e18;
		cin >> x;
		for (int i = 1; i <= n; ++i) {
			if (!x) {
				ans = min(ans, a[i]);
				continue;
			}
			if (i == n) {
				if (x & 1) {
					s += a[i] + x;
					ans = min(a[i] + x, ans);
					x--;
					s -= x / 2;
					ans = min(ans, s / n);
				} else {
					s += a[i] - x / 2;
					ans = min({ans, a[i], s / n});
				}
			} else ans = min(ans, a[i] + x), s += a[i] + x;
			if (x != 0) x--;
		}
		cout << ans << ' ';
	}
}

D2

针对 k > n k>n k>n 的情况进行优化,如果 k − n k-n kn 是偶数,那就要减 k − n 2 \dfrac{k-n}{2} 2kn,如果是奇数,就减 k − n + 1 2 \dfrac{k-n+1}{2} 2kn+1,时间复杂度 O ( 1 ) O(1) O(1)

最终的时间复杂度就是 O ( n log ⁡ n + q ) O(n\log n+q) O(nlogn+q)

代码

#include <bits/stdc++.h>
#define int long long
 
using namespace std;
const int maxn = 3e5 + 20;
 
int n, q, s, x, o, ans;
int a[maxn], f[maxn];
 
signed main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> q;
	for (int i = 1; i <= n; ++i) cin >> a[i], s += a[i];
	sort(a + 1, a + n + 1);
	fill(f + 1, f + n + 10, 1e18);
	for (int i = 1; i <= n; ++i) f[i + 1] = min(f[i], a[i]) + 1;
	while (q--) {
		cin >> x;
		if (x < n) cout << min(f[x + 1], a[x + 1]) << ' ';
		else {
			ans = 0, o = s;
			if (!((x - n) & 1)) {
				ans = f[n + 1] + x - n;
				o += n * (x * 2 - n + 1) / 2 - (x - n) / 2;
			} else {
				ans = min(f[n] + x - n + 1, a[n]);
				o += (n - 1) * (x * 2 - n + 2) / 2 - (x - n + 1) / 2; 
			}
			cout << min(ans, o / n) << ' ';
		} 
	}
}

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值