题目传送门

$Sol$

$50pts$:我们考虑$q==0$的情况,每次在所有的蚯蚓中找到一只长度最大的,这非常二叉堆。所以我们可以用一个优先队列,随便水一下就有50分。($NOIp$的分真这么好拿?)

(理论得分60分,由于种种常数等的原因,实际会达到50分)

 #include<cstdio>
#include<algorithm>
#include<queue> using namespace std; int n,m,can,u,v,t;
int tim[];
priority_queue<int>q; int main()
{
scanf("%d%d%d%d%d%d",&n,&m,&can,&u,&v,&t);
if(can==)
{
for(int i=;i<=n;i++)
{
int x=;
scanf("%d",&x);q.push(x);
}
for(int i=;i<=m;i++)
{
int tmp=q.top();q.pop();tim[i]=tmp;
int a=u*tmp/v;int b=tmp-a;
q.push(a);q.push(b);
}
for(int i=t;i<=m;i+=t)
printf("%d ",tim[i]);
printf("\n");
for(int i=;i<=n+m;i++)
{
if(q.empty()) break;
if(i%t==) printf("%d ",q.top());
q.pop();
}
}
return ;
}

50pts

$85pts$:我们不得不考虑每次切蚯蚓后其他的蚯蚓长度情况(为了拿到更多的部分分),我们不妨考虑下线段树和分块中的思想。

我们并不需要每次都把其他蚯蚓的长度增加,而是等需要他们的时候再增加。于是,我们同样在维护一个二叉堆(优先队列),但是这里面存的是还是最初的蚯蚓们长度。我们再维护一个增量即可。

另外这道题是著名的卡常数代表,开始我80分是因为开了$longlong$,有位老哥和我打暴力的方法一样,然后它用$int+double$转化卡到了85分。

 #include<cstdio>
#include<algorithm>
#include<queue> using namespace std;
typedef long long ll; ll n,m,can,u,v,t;
ll sigma;
priority_queue<ll>q; void re(ll &x)
{
x=;
char ch=getchar();
bool flag=false;
while(ch<''||ch>'') flag|=(ch=='-'),ch=getchar();
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
x=flag ? -x : x;
} int main()
{
re(n),re(m),re(can),re(u),re(v),re(t);
for(register int i=;i<=n;i++)
{
ll x=;
re(x);q.push(x);
}
for(register int i=;i<=m;i++)
{
ll tmp=q.top()+sigma;q.pop();//输出要把增量带上
if(i%t==) printf("%lld ",tmp);
ll a=1ll*u*tmp/v;ll b=tmp-a;
a-=sigma;b-=sigma;//进优先队列的都是不带增量的
a-=can;b-=can;//为了防止以后被认为在这时刻增加了 现在先减去
q.push(a);q.push(b);
sigma+=can;//继续维护增量
}
printf("\n");
for(register int i=;i<=n+m;i++)
{
if(q.empty()) break;
if(i%t==) printf("%lld ",q.top()+sigma);
q.pop();
}
return ;
}

85pts

$100pts$:正解的思维难度还是有的,先被切掉的蚯蚓长度一定比后被切掉的蚯蚓长度大。

NOIp2016 蚯蚓 【二叉堆/答案单调性】By cellur925-LMLPHP

(引用自@aiyougege,侵删)

 #include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath> using namespace std;
typedef long long ll; ll n,m,q,t,sigma;
double u,v,p;
ll qiuyin[];
queue<ll>q1,q2,qq; bool cmp(ll a,ll b)
{
return a>b;
} int main()
{
scanf("%lld%lld%lld%lf%lf%lld",&n,&m,&q,&u,&v,&t);
p=u/v;
for(int i=;i<=n;i++) scanf("%lld",&qiuyin[i]);
sort(qiuyin+,qiuyin++n,cmp);
for(int i=;i<=n;i++) qq.push(qiuyin[i]);
for(int i=;i<=m;i++)
{
ll len=,len1=,len2=;
ll qwq=-1e16-,qaq=-1e16-,orz=-1e16-;
if(!q1.empty()) qwq=q1.front();
if(!q2.empty()) qaq=q2.front();
if(!qq.empty()) orz=qq.front();
if(!q1.empty()&&qwq>=qaq&&qwq>=orz) q1.pop();
else if(!q2.empty()&&qaq>=qwq&&qaq>=orz) q2.pop();
else if(!qq.empty()&&orz>=qaq&&orz>=qwq) qq.pop(); len=max(max(qwq,qaq),orz);len+=sigma;
if(i%t==) printf("%lld ",len);
len1=floor(p*len)-q-sigma;
len2=len-floor(p*len)-q-sigma;
q1.push(len1),q2.push(len2);
sigma+=q;
}
printf("\n");
for(int i=;i<=n+m;i++)
{
ll len=,qwq=-1e16-,qaq=-1e16-,orz=-1e16-;
if(!q1.empty()) qwq=q1.front();
if(!q2.empty()) qaq=q2.front();
if(!qq.empty()) orz=qq.front();
if(!q1.empty()&&qwq>=qaq&&qwq>=orz) q1.pop();
else if(!q2.empty()&&qaq>=qwq&&qaq>=orz) q2.pop();
else if(!qq.empty()&&orz>=qaq&&orz>=qwq) qq.pop();
len=max(max(qwq,qaq),orz)+sigma;
if(i%t==) printf("%lld ",len);
}
return ;
}

但是期间奥妙重重WA了无数次,也不知怎么肥事。重敲就活过来了,可能是精度问题的锅,还需要注意下。


小结:NOIp的部分分还是给的很足的,有时还可能不小心敲成正解?第二题还是要重视,尽量多拿分。

05-11 22:39