NOIP2016 day2 t2 蚯蚓

· · 题解

NOIP2016 day2 t2 蚯蚓

“这题有一种广为人知的做法,它叫优先队列。” ——干物国大皇帝

嗯……感觉像个模拟。

朕的代码一向可读性较高,看不懂的可以在聊天栏里冒泡。如有更好的方法(简洁+高效),欢迎众帅卿靓臣上疏直谏

//没抢到Bilibili今年的拜年祭手办,心碎pianggang……

65分:优先队列

(洛谷上数据好像有点水,测出来85分,官方数据是65分)

#include<bits/stdc++.h>
using namespace std;

#define il inline

double p;
int sum;//蚯蚓总增长 
int n, m, k/*q*/, u, v, t;
priority_queue<int> q;//优先队列 

il int read()  {
  int x=0;  bool f=1;  char ch=getchar();
  while(ch<48||ch>57)  { if(ch=='-') f=0;  ch=getchar(); }
  while(ch>=48&&ch<=57)  { x=(x<<3)+(x<<1)+(ch^48);  ch=getchar(); }
  return f?x:-x;
}
template<typename T> void print(const T x)  {
  if(x >= 10)  print(x/10);
  putchar( (x%10)|48 ); 
}
template<typename T>il void put(const T x)  {
  if(x < 0)  putchar('-'), print(-x);
  else  print(x);
}


int main()  {
  freopen("input1.txt", "r", stdin);
  //freopen("output.txt", "w", stdout);

  n=read(), m=read(), k=read(), u=read(), v=read(), t=read();
  p = (double)u/v;//不要掉精度
  for(int i = 0; i < n; ++i)  {
    int a;
    a=read();
    q.push(a);
  }
  for(int i = 1; i <= m; ++i)  {
    int l = q.top()+sum;//被切的蚯蚓的长度
    if(i%t == 0)  put(l), putchar(' ');/* 输出第一排 */
    q.pop();
    sum += k;
    int nl = l*p;
    q.push(nl-sum);
    q.push(l-nl-sum); 
  }
  printf("\n");
  int tim = 0;
  while( !q.empty() )  {
    tim++;
    int l = q.top()+sum;
    if(tim%t == 0)  put(l), putchar(' ');
    q.pop();
  }

  return 0;
}

100分:手工队列

优先队列不够快,会TLE!!

仔细想想,就能发现先被切掉的蚯蚓分成的蚯蚓一定比后切掉的蚯蚓分成的蚯蚓长,这就是题目中隐含的单调性。 那么蚯蚓有如下三种状态:

  1. q: 没切的;
  2. q1: 切了的;
  3. q2: 切剩下的。

由此可得:每个模拟队列的第一个值(q[0], q1[0], q2[0])都为该队列中最大。

如此这般,用DIY的手工队列替换优先队列即可。

#include<bits/stdc++.h>
using namespace std;

#define il inline

const int N = 1e5+5, M = 7e6+5;
const int inf = 0x3f3f3f3f;
double p;
int sum;
int n, m, k, u, v, t;
int q[N], q1[M], q2[M], head, head1, head2, tail, tail1, tail2;//手工队列 

il int read()  {
  int x=0;  bool f=1;  char ch=getchar();
  while(ch<48||ch>57)  { if(ch=='-') f=0;  ch=getchar(); }
  while(ch>=48&&ch<=57)  { x=(x<<3)+(x<<1)+(ch^48);  ch=getchar(); }
  return f?x:-x;
}
template<typename T> void print(const T x)  {
  if(x >= 10)  print(x/10);
  putchar( (x%10)|48 ); 
}
template<typename T>il void put(const T x)  {
  if(x < 0)  putchar('-'), print(-x);
  else  print(x);
}


il bool cmp(int a, int b)  { return a > b; }


il int TOP()  {//相当于 q.top() 
  int x=-inf, x1=-inf, x2=-inf;
  if(head < tail)  x = q[head];
  if(head1 < tail1)  x1 = q1[head1];
  if(head2 < tail2)  x2 = q2[head2];
  if(x>=x1 && x>x2)  { head++;  return x; }//x最大 
  else if(x1 > x2)  { head1++;  return x1; }//x1最大 
  head2++;  return x2;//x2最大 
}


int main()  {
  n=read(), m=read(), k=read(), u=read(), v=read(), t=read();
  p = (double)u/v;//浮点数精度不要丢 
  tail = n;
  for(int i = 0; i < n; ++i)  q[i]=read();
  sort(q, q+n, cmp);//优先性 
  //q, q1, q2都是0基准
  for(int i = 1; i <= m; ++i)  {
    int x = TOP()+sum;
    if(i%t == 0)  put(x), putchar(' ');
    sum += k;
    int nx = p*x;
    int x1 = nx-sum, x2 = x-nx-sum;
    q1[tail1++]=x1, q2[tail2++]=x2;
  }
  putchar('\n');
  int tim = 0;
  while( ++tim<=(n+m) )
    if(tim%t == 0)  put(TOP()+sum), putchar(' ');
    else  TOP();//出队=q.pop() 

  return 0;
}