【NOIP2016D2T2蚯蚓】一道NOIP真题
就是这样的一道题。大家实在想看本题的类型可以看每篇文章下面若隐若现的标签(orz 虽然应该没什么人看蒟蒻的博客)
单调队列
Luogu2827 LOJ2362
这道题和那道合并果子基本上就是一模(mu)一样。那道题是找最小的两个果子合并,甚至都可以用堆来做,这道题堆貌似只有80分(要是叫你堆就水过去了他还干嘛orz )。
由于每一次被切的比例是固定的,那么我们可以发现一个单调性-->先被切开的两段比后被切开的两段大。这也很好证明,他们被切开就必定要错过一次增加长度,于是他们在增加的意义下是相同的,而我们是优先选择较大的切开,那么就一定有这个单调性。
于是乎我们开三个队列,表示原本队列(我们可以先sort一下保证其单调性),被切开的前一段的队列,被切开的后一段的队列,然后我们每次找出三个中最大的那个切开,再甩进队尾就可以了。
对于添加,由于是整体添加,仅仅只有刚刚切开的错过添加,那么我们完全可以整一个全局变量Q的东东,在添加进队列的时候减去这时候的Q,出来的时候加这时候的Q。
时间复杂度O(nlogn + n + m) nlogn是初始n个数sort 带过来的
#include<stdio.h> #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> using namespace std; const int maxn = 100005; int n,m,q,u,v,t; double p; int a[maxn]; queue<int>qu[3]; int tim; int Q; int main() { scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t); p=(double)u/(double)v; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } sort(a+1,a+1+n); for(int i=n;i>=1;i--) qu[0].push(a[i]); for(int i=1;i<=m;i++) { int zqmx = 0; for(int i=0;i<3;i++) { if(qu[i].size()) { zqmx = max(zqmx,qu[i].front()+Q); } } int zz; for(int i=0;i<3;i++) { if(qu[i].size()) { if(qu[i].front()+Q==zqmx) { zz=i; break; } } } if(i%t==0) { printf("%d ",zqmx); } qu[zz].pop(); int qyd = (int)floor( (double)(zqmx)*p ); Q+=q; qu[1].push(qyd-Q); qu[2].push(zqmx-qyd-Q); } puts(""); int tim = (n+m)/t; for(int i=1;i<=tim*t;i++) { int zqmx = 0; for(int i=0;i<3;i++) { if(qu[i].size()) { zqmx = max(zqmx,qu[i].front()+Q); } } int zz; for(int i=0;i<3;i++) { if(qu[i].size()) { if(qu[i].front()+Q==zqmx) { zz=i; break; } } } if(i%t==0) { printf("%d ",zqmx); } qu[zz].pop(); } }