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

题目传送门

$Sol$

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

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 
 5 using namespace std;
 6 
 7 int n,m,can,u,v,t;
 8 int tim[7000090];
 9 priority_queue<int>q;
10 
11 int main()
12 {
13     scanf("%d%d%d%d%d%d",&n,&m,&can,&u,&v,&t);
14     if(can==0)
15     {
16         for(int i=1;i<=n;i++)
17         {
18             int x=0;
19             scanf("%d",&x);q.push(x);
20         }
21         for(int i=1;i<=m;i++)
22         {
23             int tmp=q.top();q.pop();tim[i]=tmp;
24             int a=u*tmp/v;int b=tmp-a;
25             q.push(a);q.push(b);
26         }
27         for(int i=t;i<=m;i+=t)
28             printf("%d ",tim[i]);
29         printf("\n");
30         for(int i=1;i<=n+m;i++)
31         {
32             if(q.empty()) break;
33             if(i%t==0) printf("%d ",q.top());
34             q.pop();
35         }
36     }
37     return 0;
38 }
50pts

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

Chemist:线段树中最精妙的设计是什么?

我:懒标记!

Chemist:对!你就往这想。

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

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 ll n,m,can,u,v,t;
 9 ll sigma;
10 priority_queue<ll>q;
11 
12 void re(ll &x)
13 {
14     x=0;
15     char ch=getchar();
16     bool flag=false;
17     while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar();
18     while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
19     x=flag ? -x : x;
20 }
21 
22 int main()
23 {
24     re(n),re(m),re(can),re(u),re(v),re(t);
25     for(register int i=1;i<=n;i++)
26     {
27         ll x=0;
28         re(x);q.push(x);
29     }
30     for(register int i=1;i<=m;i++)
31     {
32         ll tmp=q.top()+sigma;q.pop();//输出要把增量带上 
33         if(i%t==0) printf("%lld ",tmp);
34         ll a=1ll*u*tmp/v;ll b=tmp-a;
35         a-=sigma;b-=sigma;//进优先队列的都是不带增量的 
36         a-=can;b-=can;//为了防止以后被认为在这时刻增加了 现在先减去 
37         q.push(a);q.push(b);
38         sigma+=can;//继续维护增量 
39     }
40     printf("\n");
41     for(register int i=1;i<=n+m;i++)
42     {
43         if(q.empty()) break;
44         if(i%t==0) printf("%lld ",q.top()+sigma);
45         q.pop();
46     }
47     return 0;
48 }
85pts

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

(引用自@aiyougege,侵删)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 #include<cmath> 
 5 
 6 using namespace std;
 7 typedef long long ll;
 8 
 9 ll n,m,q,t,sigma;
10 double u,v,p;
11 ll qiuyin[100090];
12 queue<ll>q1,q2,qq;
13 
14 bool cmp(ll a,ll b)
15 {
16     return a>b;
17 }
18 
19 int main()
20 {
21     scanf("%lld%lld%lld%lf%lf%lld",&n,&m,&q,&u,&v,&t);
22     p=u/v;
23     for(int i=1;i<=n;i++) scanf("%lld",&qiuyin[i]);
24     sort(qiuyin+1,qiuyin+1+n,cmp);
25     for(int i=1;i<=n;i++) qq.push(qiuyin[i]);
26     for(int i=1;i<=m;i++)
27     {
28         ll len=0,len1=0,len2=0;
29         ll qwq=-1e16-7,qaq=-1e16-7,orz=-1e16-7;
30         if(!q1.empty()) qwq=q1.front();
31         if(!q2.empty()) qaq=q2.front();
32         if(!qq.empty()) orz=qq.front();
33         if(!q1.empty()&&qwq>=qaq&&qwq>=orz) q1.pop();
34         else if(!q2.empty()&&qaq>=qwq&&qaq>=orz) q2.pop();
35         else if(!qq.empty()&&orz>=qaq&&orz>=qwq) qq.pop();
36         
37         len=max(max(qwq,qaq),orz);len+=sigma;
38         if(i%t==0) printf("%lld ",len);
39         len1=floor(p*len)-q-sigma;
40         len2=len-floor(p*len)-q-sigma;
41         q1.push(len1),q2.push(len2);
42         sigma+=q;
43     }
44     printf("\n");
45     for(int i=1;i<=n+m;i++)
46     {
47         ll len=0,qwq=-1e16-7,qaq=-1e16-7,orz=-1e16-7;
48         if(!q1.empty()) qwq=q1.front();
49         if(!q2.empty()) qaq=q2.front();
50         if(!qq.empty()) orz=qq.front();
51         if(!q1.empty()&&qwq>=qaq&&qwq>=orz) q1.pop();
52         else if(!q2.empty()&&qaq>=qwq&&qaq>=orz) q2.pop();
53         else if(!qq.empty()&&orz>=qaq&&orz>=qwq) qq.pop();
54         len=max(max(qwq,qaq),orz)+sigma;
55         if(i%t==0) printf("%lld ",len);
56     }
57     return 0;
58 }
View Code

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


 

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

posted @ 2018-10-04 14:55  cellur925&Chemist  阅读(176)  评论(0编辑  收藏  举报