CH0601 Genius ACM 倍增

题目链接

http://noi-test.zzstep.com/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0601%20Genius%20ACM

分析

每次设定一段长度为 1 1 1 的初始区间(一定合法),倍增来扩展区间右端点。

求“校验值”需要排序,只需排新加入的一段,再像归并排序那样合并两段。

注意每次扩展还要保证新的右端点不超过 N N N

AC代码

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

typedef long long ll;

inline ll read() {
	ll num = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9')
		num = num * 10 + c - '0', c = getchar();
	return num;
}

const int maxn = 5e5 + 5;

int a[maxn], tmp[maxn];

int main() {
	int t = read();
	while (t--) {
		int n = read(), m = read(), cnt = 0;
		ll k = read();
		for (int i = 1; i <= n; ++i) a[i] = read();
		int l = 1, r = 1, p = 1;
		while (l <= n) {
			while (r + p > n) p /= 2;
			for (int i = r + 1; i <= r + p; ++i) tmp[i] = a[i];
			sort(tmp + r + 1, tmp + r + p + 1);
			int lp = l, rp = r + 1;
			for (int i = l; i <= r + p; ++i) {
				if (rp > r + p || (lp <= r && a[lp] <= tmp[rp]))
					tmp[i] = a[lp++];
				else tmp[i] = tmp[rp++];
			}
			ll val = 0;
			for (int i = l; i <= l + min(m, (r + p - l + 1) / 2) - 1; ++i)
				val += pow(tmp[i] - tmp[r + p - i + l], 2);
			if (val <= k) {
				for (int i = l; i <= r + p; ++i) a[i] = tmp[i];
				r = r + p, p *= 2;
			} else p /= 2;
			if (!p) ++cnt, l = r + 1, r = l, p = 1;
		}
		printf("%d\n", cnt);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值