LOJ#2362. 「NOIP2016」蚯蚓
这题做了一下午。。感谢 hxy,VoidWalker 等神仙 qaq
85分做法
维护一个堆,里面存各个蚯蚓的长度然后按题意模拟。
对于修改每个蚯蚓长度的操作,我们并不需要在堆中一个一个修改,而是可以记录一个 \(\mathrm{sum}\),代表到当前加了多少遍 \(q\)。但如果这样存,将蚯蚓砍成两段这个操作就需要特殊处理一下,具体看代码。
此做法的时间复杂度为 \(\mathcal O(m\log n)\),可获得 85 分,开 O2 可以获得 90 分。
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<climits>
#include<algorithm>
#include<queue>
using namespace std;
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
void write(int n)
{
if(n<0)
{
putchar('-');
n=-n;
}
if(n>9) write(n/10);
putchar(n%10^48);
}
int main()
{
priority_queue<int> que;
int n=read(),m=read(),q=read(),u=read(),v=read(),t=read();
double p=u*1.0/v;
for(int i=1;i<=n;i++) que.push(read());
int sum=0;
for(int i=1;i<=m;i++)
{
int x=que.top()+sum; que.pop();
int t1=x*p,t2=x-t1;
t1-=(sum+q);
t2-=(sum+q);
que.push(t1); que.push(t2);
if(i%t==0)
{
write(x);
putchar(' ');
}
sum+=q;
}
int i=0;
putchar('\n');
while(!que.empty())
{
i++;
if(i%t==0)
{
write(que.top()+sum);
putchar(' ');
}
que.pop();
}
return 0;
}
100分做法
开三个队列,分别存蚯蚓的初始长度、砍断之后前一段的长度和砍断之后后一段的长度。通过观察,可看出这三个队列都是单调的。也就是说我们没必要开一个堆来找最长的蚯蚓,而是可以在这三个队列的队首中取 \(\max\),将这个蚯蚓砍断,然后分别存入第二、第三个队列,以此类推。这样我们就把优先队列的 \(\log\) 替换成了队列的常数,总复杂度变成了 \(\mathcal O(m)\)。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
void write(int n)
{
if(n<0)
{
putchar('-');
n=-n;
}
if(n>9) write(n/10);
putchar(n%10^48);
}
using namespace std;
queue<int> que1,que2,que3;
const int INF=0X7FFFFFFF;
inline int getmax()
{
int l1=-INF,l2=-INF,l3=-INF;
if(!que1.empty()) l1=que1.front();
if(!que2.empty()) l2=que2.front();
if(!que3.empty()) l3=que3.front();
int maxn=max(l1,max(l2,l3));
if(maxn==-INF) return -INF;
if(l1==maxn) que1.pop();
else if(l2==maxn) que2.pop();
else if(l3==maxn) que3.pop();
return maxn;
}
int a[10000010];
int main()
{
int n,m,q,u,v,t;
n=read();m=read();q=read();u=read();v=read();t=read();
double p=u*1.0/v;
int sum=0;
for(int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) que1.push(a[n-i+1]);
for(int i=1;i<=m;i++)
{
int x=getmax()+sum;
int t1=x*p,t2=x-t1;
t1-=sum+q; t2-=sum+q;
que2.push(t1);
que3.push(t2);
if(i%t==0)
{
write(x);
putchar(' ');
}
sum+=q;
}
int i=0;
putchar('\n');
while(1)
{
i++;
int ans=getmax();
if(ans==-INF) break;
if(i%t==0)
{
write(ans+sum);
putchar(' ');
}
}
return 0;
}