zoukankan      html  css  js  c++  java
  • 队列大成题——蚯蚓(洛谷)

    先看题目:

    本题中,我们将用符号 lfloor c floorc⌋ 表示对 cc 向下取整,例如:lfloor 3.0 floor = lfloor 3.1 floor = lfloor 3.9 floor = 33.0=3.1=3.9=3。

    蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。

    蛐蛐国里现在共有 nn 只蚯蚓(nn 为正整数)。每只蚯蚓拥有长度,我们设第 ii 只蚯蚓的长度为 a_iai (i=1,2,dots,ni=1,2,,n),并保证所有的长度都是非负整数(即:可能存在长度为 00 的蚯蚓)。

    每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数 pp(是满足 0 < p < 10<p<1 的有理数)决定,设这只蚯蚓长度为 xx,神刀手会将其切成两只长度分别为 lfloor px floorpx⌋ 和 x - lfloor px floorxpx⌋ 的蚯蚓。特殊地,如果这两个数的其中一个等于 00,则这个长度为 00 的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加 qq(是一个非负整常数)。

    蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 mm 秒才能到来……(mm 为非负整数)

    蛐蛐国王希望知道这 mm 秒内的战况。具体来说,他希望知道:

    • mm 秒内,每一秒被切断的蚯蚓被切断前的长度(有 mm 个数);
    • mm 秒后,所有蚯蚓的长度(有 n + mn+m 个数)。

    蛐蛐国王当然知道怎么做啦!但是他想考考你……

    输入格式

    第一行包含六个整数 n,m,q,u,v,tn,m,q,u,v,t,其中:n,m,qn,m,q 的意义见【问题描述】;u,v,tu,v,t 均为正整数;你需要自己计算 p=u / vp=u/v(保证 0 < u < v0<u<v);tt 是输出参数,其含义将会在【输出格式】中解释。

    第二行包含 nn 个非负整数,为 a_1, a_2, dots, a_na1,a2,,an,即初始时 nn 只蚯蚓的长度。

    同一行中相邻的两个数之间,恰好用一个空格隔开。

    保证 1 leq n leq 10^51n105,0 leq m leq 7 imes 10^60m7×106,0 < u < v leq 10^90<u<v109,0 leq q leq 2000q200,1 leq t leq 711t71,0 leq a_i leq 10^80ai108。

    输出格式

    第一行输出 left lfloor frac{m}{t} ight floortm⌋ 个整数,按时间顺序,依次输出第 tt 秒,第 2t2t 秒,第 3t3t 秒,……被切断蚯蚓(在被切断前)的长度。

    第二行输出 left lfloor frac{n+m}{t} ight floortn+m⌋ 个整数,输出 mm 秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第 tt,第 2t2t,第 3t3t,……的长度。

    同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。

    请阅读样例来更好地理解这个格式。

    输入输出样例

    输入 #1
    3 7 1 1 3 1
    3 3 2
    输出 #1
    3 4 4 4 5 5 6
    6 6 6 5 5 4 4 3 2 2
    输入 #2
    3 7 1 1 3 2
    3 3 2
    输出 #2
    4 4 5
    6 5 4 3 2
    输入 #3
    3 7 1 1 3 9
    3 3 2
    输出 #3
    //空行
    2

    说明/提示

    【样例解释1】

    在神刀手到来前:33只蚯蚓的长度为3,3,23,3,2。

    11秒后:一只长度为33的蚯蚓被切成了两只长度分别为11和22的蚯蚓,其余蚯蚓的长度增加了11。最终44只蚯蚓的长度分别为(1,2),4,3(1,2),4,3。括号表示这个位置刚刚有一只蚯蚓被切断

    22秒后:一只长度为44的蚯蚓被切成了11和33。55只蚯蚓的长度分别为:2,3,(1,3),42,3,(1,3),4。

    3秒后:一只长度为44的蚯蚓被切断。66只蚯蚓的长度分别为:3,4,2,4,(1,3)3,4,2,4,(1,3)。

    44秒后:一只长度为44的蚯蚓被切断。77只蚯蚓的长度分别为:4,(1,3),3,5,2,44,(1,3),3,5,2,4。

    55秒后:一只长度为55的蚯蚓被切断。88只蚯蚓的长度分别为:5,2,4,4,(1,4),3,55,2,4,4,(1,4),3,5。

    66秒后:一只长度为55的蚯蚓被切断。99只蚯蚓的长度分别为:(1,4),3,5,5,2,5,4,6(1,4),3,5,5,2,5,4,6。

    77秒后:一只长度为66的蚯蚓被切断。1010只蚯蚓的长度分别为:2,5,4,6,6,3,6,5,(2,4)2,5,4,6,6,3,6,5,(2,4)。所以,77秒内被切断的蚯蚓的长度依次为3,4,4,4,5,5,63,4,4,4,5,5,6。77秒后,所有蚯蚓长度从大到小排序为6,6,6,5,5,4,4,3,2,26,6,6,5,5,4,4,3,2,2

    【样例解释2】

    这个数据中只有t=2t=2与上个数据不同。只需在每行都改为每两个数输出一个数即可。

    虽然第一行最后有一个66没有被输出,但是第二行仍然要重新从第二个数再开始输出。

    【样例解释3】

    这个数据中只有t=9t=9与上个数据不同。

    注意第一行没有数要输出,但也要输出一个空行。

    【数据范围】

    完成版的题目我搬过来了,大家直接看就好

    这道题直接模拟用优先队列是一定会TLE的

    所以我们一定要找别的方法

    关键点: 发现此题中隐含的单调性.

      发现先被切掉的蚯蚓分成的蚯蚓一定比后切掉的蚯蚓分成的蚯蚓大.   假设这两只蚯蚓分别为a,ba,b,其中a>ba>b.那么它被切成a_1,a_2a1,a2. t秒后, bb被切成了b_1,b_2b1,b2.此时a_1,a_2a1,a2的长度为l_{a_1}+t=pl_{a}+t,l_{a_2}+t=(1-p)l_a+tla1+t=pla+t,la2+t=(1p)la+t.而b_1,b_2b1,b2的长度却为p(l_b+t),(1-p)(1_b+t)p(lb+t),(1p)(1b+t), 容易看出l_{a_1}>l_{b_1},l_{a_2}>l_{b_2}la1>lb1,la2>lb2.也就是说根本不需要用一个堆来维护, 它本来就具有一定单调性.

      那么就是说如果蚯蚓a_1,a_2,cdots,a1,a2,,满足a_1>a_2>cdotsa1>a2>⋯,那么以此分成两只a_{11},a_{12},a_{21},a_{22},cdotsa11,a12,a21,a22,⋯.那么a_{12}>a_{22}>cdots,a_{11}>a_{21}>cdotsa12>a22>,a11>a21>

      那么就可以将这两堆依次存储, 加上还没被切过的蚯蚓.每次要切时在这三堆里面选择最大的, 切完再依次放回去.   所以这么做时间复杂度为O(m).再优化一下细节基本上就没问题了.

      结论: 善于发现题目中隐含的单调性.

    先看一个代码:

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <queue>
     4 #include <cmath>
     5 using namespace std;
     6 int n,m,q,u,v,t;
     7 queue<int> q1,q2,q3;
     8 int a[100005];
     9 priority_queue<int> ans;
    10 bool cmp(const int &a,const int &b){
    11     return a>b;
    12 }
    13 int main(){
    14     //freopen("a.in","r",stdin);
    15     scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
    16     double p=0;p=(double)u/v;
    17     for(int i=1;i<=n;i++){
    18         scanf("%d",&a[i]);
    19     }
    20     sort(a+1,a+n+1,cmp);
    21     for(int i=1;i<=n;i++){
    22         q1.push(a[i]);
    23     }
    24     int top=0,now=0;
    25     for(int i=1;i<=m;i++){
    26         int x1=-0x3f3f3f3f,x2=-0x3f3f3f3f,x3=-0x3f3f3f3f;
    27         if(q1.size())x1=q1.front();
    28         if(q2.size())x2=q2.front();
    29         if(q3.size())x3=q3.front();
    30         if(x1>=x2&&x1>=x3){top=x1;q1.pop();}
    31         else if(x2>=x1&&x2>=x3){top=x2;q2.pop();}
    32         else {top=x3;q3.pop();}
    33         top+=now;
    34         int p1=floor(p*(double)top);long long p2=top-p1;
    35         now+=q;
    36         p1-=now;p2-=now;
    37         q2.push(p1);q3.push(p2);
    38         if(i%t==0)printf("%d ",top);
    39     }
    40     printf("
    ");
    41     while(q1.size()){
    42         ans.push(q1.front());
    43         q1.pop();
    44     }
    45     while(q2.size()){
    46         ans.push(q2.front());
    47         q2.pop();
    48     }
    49     while(q3.size()){
    50         ans.push(q3.front());
    51         q3.pop();
    52     }
    53     int tot=0;
    54     while(ans.size()){
    55         tot++;
    56         if(tot%t==0){
    57             printf("%d ",ans.top()+now);
    58         }
    59         ans.pop();
    60     }
    61     return 0;
    62 }

    为什么要看这个代码,

    因为这个代码90分,但是是按照单调队列写的,

    为啥,因为用的是STL里的容器,

    所以一定要手模队列,千万不要为了省事而去用STL

    太坑了。

    当然也可写读入优化

    但是也仅仅只能在洛谷上拿到100分

    不是数据水,是洛谷评测机太牛逼。

    换个网站你就挂了。

    下面是代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<queue>
     6 using namespace std;
     7 #define ll long long 
     8 #define maxn 7000005
     9 int a[maxn];
    10 ll q1[maxn],q2[maxn];
    11 int cmp(int a,int b){ return a>b; }
    12 int main(){
    13     //freopen("a.in","r",stdin);
    14     int n,m,q,u,v,t;
    15     scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
    16     for(int i=1;i<=n;++i){
    17         scanf("%d",&a[i]);
    18     }
    19     sort(a+1,a+1+n,cmp);
    20     int HA=1,TA=n,HX=1,HD=1,TX=0,TD=0;
    21     ll no=0,all=0;
    22     int S=m;
    23     while(S--){
    24         no++;
    25         ll ans=-0x3f3f3f3f3f3f3f3f;
    26         if(HA<=TA && a[HA]>=ans) ans=a[HA];
    27         if(HX<=TX && q1[HX]>=ans) ans=q1[HX];
    28         if(HD<=TD && q2[HD]>=ans) ans=q2[HD];
    29         if(a[HA]==ans && HA<=TA) HA++;
    30         else if(q1[HX]==ans && HX<=TX) HX++;
    31         else HD++;
    32         ans+=all;
    33         if(no%t==0) printf("%lld ",ans);
    34         ll left=u*ans/v;
    35         ll right=ans-left;
    36         all=no*q;
    37         left-=all,right-=all;
    38         q1[++TX]=min(left,right);
    39         q2[++TD]=max(left,right);
    40     }
    41     printf("
    ");
    42     int now=n+m;
    43     for(int i=1;i<=now;++i){
    44         ll ans=-0x3f3f3f3f3f3f3f3f;
    45         if(HA<=TA && a[HA]>=ans) ans=a[HA];
    46         if(HX<=TX && q1[HX]>=ans) ans=q1[HX];
    47         if(HD<=TD && q2[HD]>=ans) ans=q2[HD];
    48         if(a[HA]==ans && HA<=TA) HA++;
    49         else if(q1[HX]==ans && HX<=TX) HX++;
    50         else HD++;
    51         if(i%t==0) printf("%lld ",ans+all);
    52     }
    53     printf("
    ");
    54     return 0;
    55 }

    当然这样已经可以A了

    所以这道题也就结束了

    如果在vjudge上实在过不了,

    可以去洛谷,振强自信心。

  • 相关阅读:
    461. Hamming Distance
    342. Power of Four
    326. Power of Three
    368. Largest Divisible Subset java solutions
    95. Unique Binary Search Trees II java solutions
    303. Range Sum Query
    160. Intersection of Two Linked Lists java solutions
    88. Merge Sorted Array java solutions
    67. Add Binary java solutions
    14. Longest Common Prefix java solutions
  • 原文地址:https://www.cnblogs.com/DZN2004/p/12717321.html
Copyright © 2011-2022 走看看