题目描述:
输入
输出
思路分析——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(" "); 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 }
思路分析——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(" "); 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(" "); 60 return 0; 61 }