洛谷P2827,NOIP2016 蚯蚓

洛谷P2827,NOIP2016 蚯蚓

题目

传送门

思路

80分

考虑优先队列:

但是蚯蚓的长度是变化的,如果每一次操作都修改所有蚯蚓的长度,必然超时.但是每一次所有蚯蚓中,只有被斩断生成的两个没有+q,其它所有蚯蚓长度均+q.不难想到,用优先队列捆绑两个值:len表示被压入优先队列时的长度,t表示被压入优先队列的时间,如果当前时间为i,那么当前蚯蚓的实际长度(考虑当前秒蚯蚓的长度已经加上q)就是len + (i - t) * q.

关于重载运算符:把len和t捆绑在node类型中,对于node类型的变量a和b,当前时间为i

则a当前的长度为
a . l e n + ( i − a . t ) ⋅ q = a . l e n + i ⋅ q + a . t ⋅ q a.len+(i-a.t)\cdot q=a.len+i\cdot q +a.t\cdot q a.len+(ia.t)q=a.len+iq+a.tq
b当前的长度为
b . l e n + ( i − a . t ) ⋅ q = b . l e n + i ⋅ q + b . t ⋅ q b.len+(i-a.t)\cdot q=b.len+i\cdot q +b.t\cdot q b.len+(ia.t)q=b.len+iq+b.tq
若a当前长度小于b当前长度
a . l e n + i ⋅ q + a . t ⋅ q < b . l e n + i ⋅ q + b . t ⋅ q a.len+i\cdot q +a.t\cdot q < b.len+i\cdot q +b.t\cdot q a.len+iq+a.tq<b.len+iq+b.tq
化简:
a . l e n + a . t ⋅ q < b . l e n + b . t ⋅ q a.len +a.t\cdot q < b.len +b.t\cdot q a.len+a.tq<b.len+b.tq
所以,比较当前长度与当前时间无关,写成代码:

struct node{
	int len , t;
	bool operator < (const node &b)const{
		return (len - t * q) > (b.len - b.t * q);
	}
};

剩下的不再赘述,直接模拟即可

100分

根据题目的性质,若一条蚯蚓A的长度大于等于另一条蚯蚓B的长度,那么分裂后必有
max ⁡ ( A 1 , A 2 ) > = max ⁡ ( B 1 , B 2 ) , min ⁡ ( A 1 , A 2 ) > = min ⁡ ( B 1 , B 2 ) \max(A1,A2)>=\max(B1,B2),\min(A1,A2)>=\min(B1,B2) max(A1,A2)>=max(B1,B2),min(A1,A2)>=min(B1,B2)
A1,A2表示A蚯蚓分裂后的两条蚯蚓

我们定义两个node类型的队列q1,q2.条蚯蚓分裂后较长的一条和较短的一条分别存入q1,q2(具体哪个放长的哪个放短的都一样,我的程序里也没有仔细考虑这个).根据上述性质,经过一点处理,不用大根堆也能维护q1,q2有序

剩下的就是一堆细节问题了,请自行体会,研究.

代码

80分

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
int read() {
	int re = 0 , sig = 1;
	char c = getchar();
	while(c < '0' || c > '9'){
		if(c == '-')sig = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9'){
		re = (re << 1) + (re << 3) + c - '0';
		c = getchar();
	}
	return re * sig;
}
int n , m , q , u , v , t;
struct node{
	int len , t;
	bool operator < (const node &b)const{
		return (len - t * q) < (b.len - b.t * q);
	}
};
inline node pus(int len , int t) {
	node tmp;
	tmp.len = len , tmp.t = t;
	return tmp;
}
priority_queue <node> que;
int main() {
	
	n = read();	m = read();	q = read();	u = read();	v = read();	t = read();
	double p = 1.0 * u / v;
	for(int i = 1 ; i <= n ; i++){
		int len = read();
		que.push(pus(len , 0));
	}
		
	for(int i = 1 ; i <= m ; i++) {
		node k = que.top();
		que.pop();
		k.len += (i - k.t - 1) * q;
		if(i % t == 0)
			printf("%d " , k.len);
		
		que.push(pus((int)k.len * p , i));
		que.push(pus(k.len - (int)(k.len * p) , i));
	}
	putchar('\n');
	for(int i = 1 ; i <= m + n ; i++) {
		if(i % t == 0)
		{
			node k = que.top();
			printf("%d " , k.len + q * (m - k.t));
		}
		que.pop();
	}
	return 0;
}

100分

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
int read() {
	int re = 0 , sig = 1;
	char c = getchar();
	while(c < '0' || c > '9'){
		if(c == '-')sig = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9'){
		re = (re << 1) + (re << 3) + c - '0';
		c = getchar();
	}
	return re * sig;
}
int n , m , q , u , v , t;
struct node{
	int len , t;
	bool operator < (const node &b)const{
		return (len - t * q) > (b.len - b.t * q);
	}
};
inline node pus(int len , int t) {
	node tmp;
	tmp.len = len , tmp.t = t;
	return tmp;
}
struct Queue{
	int h , t;
	node a[10000000];
	void init(){
		h = t = 0;
	}
	inline node front() {
		return a[h];
	}
	inline void push(int len , int t_) {
		a[t].len = len , a[t].t = t_;
		t++;
	}
	inline void pop() {
		++h;
	}
	inline bool empty() {
		return h == t;
	}
	inline void sort_() {
		sort(a + h , a + t);
	}
	inline void print() {
		for(int i = h ; i < t ; i++)
			printf("%d,%d \t" , a[i].len , a[i].t);
		cout << endl;
	}
	bool check() {
		for(int i = h ; i < t ; i++)
			if(a[i] < a[i]) return false;
		return true;
	}
};
Queue q1 , q2 , q0;
node maxx() {//在队列不为空的情况下,寻找三个队列中队头元素最大的那个队列,并弹出,返回该元素
	int key1 , key2 , key0;
	key0 = (q0.empty() ? -(1 << 29) : (q0.a[q0.h].len - q0.a[q0.h].t * q));
	key1 = (q1.empty() ? -(1 << 29) : (q1.a[q1.h].len - q1.a[q1.h].t * q));
	key2 = (q2.empty() ? -(1 << 29) : (q2.a[q2.h].len - q2.a[q2.h].t * q));
	node tmp;
	if(key0 > key1) {//key0 > key1
		if(key0 > key2) {//key0 > key2
			tmp = q0.front();
			q0.pop();
		}
		else {//keu2 > key0 > key1
			tmp = q2.front();
			q2.pop();
		}
	}
	else {//key1 > key0
		if(key1 > key2) {//key1 > key2
			tmp = q1.front();
			q1.pop();
		}
		else {//key2 > key1 > key0
			tmp = q2.front();
			q2.pop();
		}
	}
	return tmp;
}
int main() {
	n = read();	m = read();	q = read();	u = read();	v = read();	t = read();
	double p = 1.0 * u / v;
	for(int i = 1 ; i <= n ; i++){
		int len = read();
		q0.push(len , 0);//定义q0临时存放输入的蚯蚓
	}
	q0.sort_();//保证有序
	
	for(int i =  1 ; i <= m ; i++) {
		node k = maxx();
		k.len += (i - k.t - 1) * q;
		if(i % t == 0)
			printf("%d " , k.len);
		
		int tmp1 = (int)k.len * p;
		int tmp2 = k.len - (int)(k.len * p);//这里要注意强制转换的时间(我在这里浪费了很多调试的时间)
		if(tmp1 < tmp2) {
			int tmp = tmp1;
			tmp1 = tmp2;
			tmp2 = tmp;
		}
		q1.push(tmp2 , i);//分别存放长/短蚯蚓
		q2.push(tmp1 , i);
	}
	putchar('\n');
	node k;
	for(int i = 1 ; i <= m + n ; i++) {
		k = maxx();
		if(i % t == 0)
		{
			printf("%d " , k.len + q * (m - k.t));
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值