洛谷P2827,NOIP2016 蚯蚓
题目
思路
80分
考虑优先队列:
但是蚯蚓的长度是变化的,如果每一次操作都修改所有蚯蚓的长度,必然超时.但是每一次所有蚯蚓中,只有被斩断生成的两个没有+q,其它所有蚯蚓长度均+q.不难想到,用优先队列捆绑两个值:len表示被压入优先队列时的长度,t表示被压入优先队列的时间,如果当前时间为i,那么当前蚯蚓的实际长度(考虑当前秒蚯蚓的长度已经加上q)就是len + (i - t) * q.
关于重载运算符:把len和t捆绑在node类型中,对于node类型的变量a和b,当前时间为i
则a当前的长度为
\[a.len+(i-a.t)\cdot q=a.len+i\cdot q +a.t\cdot q
\]
b当前的长度为
\[b.len+(i-a.t)\cdot q=b.len+i\cdot q +b.t\cdot q
\]
若a当前长度小于b当前长度
\[a.len+i\cdot q +a.t\cdot q < b.len+i\cdot q +b.t\cdot q
\]
化简:
\[a.len +a.t\cdot q < b.len +b.t\cdot q
\]
所以,比较当前长度与当前时间无关,写成代码:
struct node{
int len , t;
bool operator < (const node &b)const{
return (len - t * q) > (b.len - b.t * q);
}
};
剩下的不再赘述,直接模拟即可
100分
根据题目的性质,若一条蚯蚓A的长度大于等于另一条蚯蚓B的长度,那么分裂后必有
\[\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;
}