NOIP提高组2016——蚯蚓
【题目描述】:
蚯蚓
思路:
我觉得堆的思路还是比较容易看得出来的,毕竟题面描述说每次取最大的,砍成两截在扔进堆里,然后GG ,还是有\(80dpts\)(真水)
#include<cstdio>
#include<queue>
#include<cmath>
#define F(x) floor(1.0*x);
using namespace std;
int n,m,q,u,v,t;
const int MAXN = 100005;int grow = 0;
int line1[MAXN],uu=0;int line2[MAXN],vv=0;
struct Node{
int val,cut;//cut保存的是上一次被切的时候,那么这条蚯蚓的长度就是(grow - x.cut) * q
bool operator < ( const Node &a)const{
return val + (grow - cut) * q < a.val + (grow - a.cut) * q;
}
};Node check[MAXN];
priority_queue<Node>Q;
int main(){
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
for(int i=1;i<=n;++i){
int a;scanf("%d",&a);
Node aa;aa.val = a;aa.cut = 0;
Q.push(aa);
}
double p = 1.0*u/v;
for(int i=1;i<=m;++i){
Node x = Q.top() ;Q.pop() ;
x.val += (grow - x.cut) * q;//当前长度
if(i % t == 0) line1[++uu] = x.val;
int l = F(p*x.val);int r = x.val - l;
grow++;
Node y;y.val = l;y.cut = i;
Q.push(y) ;
y.val = r;y.cut = i;
Q.push(y);
}
for(int i=1;i<uu;++i) printf("%d ",line1[i]);
if(uu ^ 0) printf("%d",line1[uu]);puts("");
for(int i=1;i<=n+m;++i){
if(i % t == 0){
Node a = Q.top() ;
int val = a.val + (grow - a.cut) * q;
line2[++vv] = val;
}
Q.pop() ;
}
for(int i=1;i<vv;++i) printf("%d ",line2[i]);
if(vv ^ 0) printf("%d",line2[vv]);
return 0;
}
然后思考一下正解,因为堆每次\(push\)和\(pop\)它自身都要维护一下,这儿就有活生生的\(log_n\)的复杂度,但转念一想,为什么要维护堆,是为了维护它的单调性,但是单调性。。。。
我们发现,先把这些蚯蚓按照初始长度排序之后,它们会满足以下性质:
- 先被切的一定不比后被切的短(包括长的一段和短的一段)
- 一只蚯蚓被切断后,两部分长度一定不会超过原长度
那么先把初始长度排序,然后拿三个数组分别存:还没切的蚯蚓,切了后长的一段,切了后短的一段。每次要切的蚯蚓就是三个数组之首的最大值,这样就省掉了\(log_n\)的复杂度,转而变成的\(O(1)\)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define F(x) floor(1.0*x)
using namespace std;
int n,m,q,u,v,t;
const int MAXN = 100005;
const int MAXM = 7000005;
int a[MAXN];int l[MAXM];//保留长的那段
int s[MAXM];//保留短的那段
int uu = 0,vv = 0;int ans[MAXN+MAXM];int line1[MAXN],line2[MAXN];
int cuta[MAXN];int cutl[MAXM];
int cuts[MAXM];
inline bool cmp(int a,int b){
return a > b;
}
inline int cutwho(int a,int b,int c){
if(a >= b && a >= c) return 1;
if(b >= a && b >= c) return 2;
if(c >= a && c >= b) return 3;
}
int main(){
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
memset(cuta,0,sizeof cuta);
double p = 1.0*u/v;
sort(a+1,a+1+n,cmp);
int ha=1,hl=1,hs=1;
int ta=n,tl=0,ts=0;
int grow = 0;
for(int i=1;i<=m;++i){
int x = a[ha] + (grow - cuta[ha]) * q;
int y = l[hl] + (grow - cutl[hl]) * q;
int z = s[hs] + (grow - cuts[hs]) * q;
if(ha > ta) x = -1;
if(hl > tl) y = -1;
if(hs > ts) z = -1;
int who = cutwho(x,y,z);
if(i % t == 0) line1[++uu] = max(max(x , y) , z);
int ll , rr;
switch (who){
case 1:{
ll = F(p*x);rr = x - ll;
if(ll >= rr) l[++tl] = ll,s[++ts] = rr;
else l[++tl] = rr,s[++ts] = ll;
cutl[tl] = cuts[ts] = i;
ha++;
break;
}
case 2:{
ll = F(p*y);rr = y - ll;
if(ll >= rr) l[++tl] = ll,s[++ts] = rr;
else l[++tl] = rr,s[++ts] = ll;
cutl[tl] = cuts[ts] = i;
hl++;
break;
}
case 3:{
ll = F(p*z);rr = z - ll;
if(ll >= rr) l[++tl] = ll,s[++ts] = rr;
else l[++tl] = rr,s[++ts] = ll;
cutl[tl] = cuts[ts] = i;
hs++;
break;
}
}
grow++;
}
int o = 0;
while(ha<=ta || hl<=tl || hs<=ts){
int x = a[ha] + (grow - cuta[ha]) * q;
int y = l[hl] + (grow - cutl[hl]) * q;
int z = s[hs] + (grow - cuts[hs]) * q;
if(ha > ta) x = -1;
if(hl > tl) y = -1;
if(hs > ts) z = -1;
int who = cutwho(x,y,z);
ans[++o] = max(max(x , y) , z);
switch (who){
case 1:{
ha++;
break;
}
case 2:{
hl++;
break;
}
case 3:{
hs++;
break;
}
}
}
for(int i=1;i<uu;++i) printf("%d ",line1[i]);
if(uu) printf("%d",line1[uu]);puts("");
for(int i=t;i<=o;i+=t){
line2[++vv] = ans[i];
}
for(int i=1;i<vv;++i) printf("%d ",line2[i]);
if(vv) printf("%d",line2[vv]);
return 0;
}
\(1316ms\),还是挺快。。