洛谷P2827 NOIP2016 蚯蚓

题目描述:

 

输入 

 

 

输出 

 

 

 

思路分析——70分写法:

  看到每次取出最大值,第一眼想到的就是优先队列,我们可以每一次取完队首元素后将其分开后两段的长度进行计算,再放入队列之中即可但题目中要求,除被切开的蚯蚓外,其余蚯蚓长度要变长,每次把队中元素取出并加上q再放入队中?不用说我们也知道这是不行的,那我们可以考虑定义一个tap来表示当前队内蚯蚓的长度增加的总的长度,每次从队首取出元素,给它加上tap,使它变为它应该的此时的长度,在计算为两段之后将每一段的长度再减去tap的基础上再减一个q(因为其他数都加上了q,相当于队外的元素减q),tap+=q,之后以此类推;之后按照要求输出对应排名的蚯蚓长度即可。

附上代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 using namespace std;
 6 const int N=1e7+10;
 7 struct Qiuyin{
 8     long long length;
 9     Qiuyin(int a){
10         length=a;
11     }
12     bool operator < (const Qiuyin& a)const{  //重载运算符,方便用优先队列 
13         return a.length>length;
14     }
15 };
16 int n,m,q,u,v,t;
17 priority_queue<Qiuyin>p;
18 int main(){
19     scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
20     for(int i=1;i<=n;++i){
21         int x;
22         scanf("%d",&x);
23         p.push(Qiuyin(x));
24     }
25     double cnt=(double)u/(double)v;
26     int cnt1=t,cnt2=t;  //cnt1,2分别用于记录当前操作到何值时需要输出 
27     long long tap=0;
28     for(int i=1;i<=m;++i){
29         if(i==cnt1){
30             printf("%lld ",p.top().length+tap);
31             cnt1+=t;
32         }
33         int t=p.top().length+tap; p.pop(); //复原队首元素 
34         tap+=q;  //更新tap 
35         int a=(double)t*cnt;
36         p.push(Qiuyin(a-tap));p.push(Qiuyin(t-a-tap)); //加入队中时要减tap 
37     }
38     printf("\n");
39     for(int i=1;i<=m+n;++i){
40         if(i==cnt2){  //以此输出规定排名长度 
41             printf("%lld ",p.top().length+tap);
42             cnt2+=t;
43         }
44         p.pop();
45     }
46     return 0;
47 }
View Code

思路分析——100分写法:

  这道题之中先后插入队中的元素隐含着单调性,我们设先后取出a,b两个元素,由于大的先取,则必有a>=b,我们设题目中的计算切后长度的分数为p,则之后a分为a*p和a-a*p(即a*(1-p))两部分,b分为b*p和b-b*p(即b*(1-p))两部分,因为a>=b,则必有a*p>=b*p;a*(1-p)>=b*(1-p),我们开三个数组,一个储存原数组,sort一遍使它内部元素单调递减(不严格),另两个分别装x*p和x-x*p,每次从队首取元素时,比较三个数组中首指针指向的元素中最大的一个,将最大的取出(并将其首指针+1),分完之后再分别装入两个数组(放在队尾以保证首元素最大)中,之后按要求输出即可(仿照70分写法)。

 附上代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=1e7+10;
 6 int origin[N],cut1[N],cut2[N];
 7 int n,m,q,u,v,t;
 8 int temp=0;
 9 int front_o=1,front_c1=1,front_c2=1;//front表示不同数组的首指针,便于查询数组中z最大值。 
10 int top1,top2;//用于向数组中添加元素 
11 bool cmp(int a,int b){ //降序排列 
12     return a>b;
13 }
14 int seek_max(){  //查询并弹出相应队列一体机 
15     int Max=-1,t; //t用于记录元素所属数组 
16     if(Max<origin[front_o]+temp&&front_o<=n){ //千万注意首指针的取值范围 
17         Max=origin[front_o]+temp;
18         t=1;
19     }
20     if(Max<cut1[front_c1]+temp&&front_c1<=top1){
21         Max=cut1[front_c1]+temp;
22         t=2;
23     }
24     if(Max<cut2[front_c2]+temp&&front_c2<=top2){
25         Max=cut2[front_c2]+temp;
26         t=3;
27     }
28     if(t==1) front_o++;  //弹出首元素 
29     else if(t==2) front_c1++;
30     else front_c2++;
31     return Max;
32 }
33 int main(){
34     scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
35     double cnt=(double)u/(double)v;
36     for(int i=1;i<=n;++i){
37         scanf("%d",&origin[i]);
38     }
39     int cnt1=t,cnt2=t;
40     sort(origin+1,origin+1+n,cmp);
41     for(int i=1;i<=m;++i){
42         int Max=seek_max();
43         if(i==cnt1){
44             printf("%d ",Max);
45             cnt1+=t;
46         }
47         temp+=q;
48         int a=(double)Max*cnt,b=Max-a;  //类似70分写法 
49         cut1[++top1]=a-temp;cut2[++top2]=b-temp;
50     }
51     printf("\n");
52     for(int i=1;i<=n+m;++i){
53         int Max=seek_max();  //类似70分写法 
54         if(i==cnt2){
55             cnt2+=t;
56             printf("%d ",Max);
57         }
58     }
59     printf("\n");
60     return 0;
61 } 
View Code

 

posted @ 2020-04-16 15:41  19502-李嘉豪  阅读(138)  评论(0)    收藏  举报