[NOIP2016]蚯蚓 乱搞

探讨了在给定线段集合中,如何通过特定的切割规则和增量操作,维护线段长度的变化,并求解特定时刻线段长度总和的问题。采用三个序列分别存储原始线段、切割部分和剩余部分,通过比较队列头部元素确定每一步操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
你有n个线段,每一秒你要拿出来最长的一个线段切成两段长度为⌊p∗u⌋\lfloor{p*u}\rfloorpuu−⌊p∗u⌋u-\lfloor{p*u}\rfloorupu两段(其中u是线段长,p是一个大于0小于1的实数)没被切的线段长度加q。问和第k秒的切割线段切割前的长度和m秒后的n+m条线段的长度。


Sample Input
3 7 1 1 3 1
3 3 2


Sample Output
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2


我们开三个序列维护。
第一个序列存原数,第二个序列存⌊p∗u⌋\lfloor{p*u}\rfloorpu,第三个序列存u−⌊p∗u⌋u-\lfloor{p*u}\rfloorupu
每次取三个队列队头最大值即可,易证不说了。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}
void put(int x) {
	if(x == 0) {putchar('0'); return ;}
    int num = 0; char c[15];
    while(x) c[++num] = (x % 10) + '0', x /= 10;
    while(num) putchar(c[num--]);
}

int len, a[110000];
int Q[3][7100001], l[3], r[3];

int main() {
	int n = read(), m = read(), q = read(), u = read(), v = read(), t = read();
	double p = (double)u / v;
	for(int i = 1; i <= n; i++) a[i] = read();
	sort(a + 1, a + n + 1); l[0] = 1, r[0] = n;
	l[1] = 1, r[1] = 0, l[2] = 1, r[2] = 0;
	for(int i = 1; i <= n; i++) Q[0][n - i + 1] = a[i];
	for(int i = 1; i <= m; i++) {
		int h1 = -2147483647, h2 = -2147483647, h3 = -2147483647;
		if(l[0] <= r[0]) h1 = Q[0][l[0]];
		if(l[1] <= r[1]) h2 = Q[1][l[1]];
		if(l[2] <= r[2]) h3 = Q[2][l[2]];
		if(h1 >= h2 && h1 >= h3) {
			int o = h1 + (i - 1) * q;
			if(i % t == 0) put(o);
			++l[0]; int hh = int(o * p);
			Q[1][++r[1]] = hh - i * q, Q[2][++r[2]] = o - hh - i * q;
		} else if(h2 >= h1 && h2 >= h3) {
			int o = h2 + (i - 1) * q;
			if(i % t == 0) put(o);
			++l[1]; int hh = int(o * p);
			Q[1][++r[1]] = hh - i * q, Q[2][++r[2]] = o - hh - i * q;
		} else {
			int o = h3 + (i - 1) * q;
			if(i % t == 0) put(o);
			++l[2]; int hh = int(o * p);
			Q[1][++r[1]] = hh - i * q, Q[2][++r[2]] = o - hh - i * q;
		} if(i % t == 0 && i != m / t * t) putchar(' ');
	} puts("");
	for(int i = 1; i <= n + m; i++) {
		int h1 = -2147483647, h2 = -2147483647, h3 = -2147483647;
		if(l[0] <= r[0]) h1 = Q[0][l[0]];
		if(l[1] <= r[1]) h2 = Q[1][l[1]];
		if(l[2] <= r[2]) h3 = Q[2][l[2]];
		if(h1 >= h2 && h1 >= h3) {
			if(i % t == 0) put(h1 + m * q);
			++l[0];
		} else if(h2 >= h1 && h2 >= h3) {
			if(i % t == 0) put(h2 + m * q);
			++l[1];
		} else {
			if(i % t == 0) put(h3 + m * q);
			++l[2];
		} if(i % t == 0 && i != (n + m) / t * t) putchar(' ');
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值