zoukankan      html  css  js  c++  java
  • [noip2016]蚯蚓<单调队列+模拟>

    题目链接:https://vijos.org/p/2007

    题目链接:https://www.luogu.org/problem/show?pid=2827#sub

    说实话当两个网站给出AC后,我很感动。。。。这题啊,思路容易想到,就是小细节太烦了。。。。。

    【思路】

    这道题要开三个队列,而且需要证明到一个点才能够做。。

    就是先切的蚯蚓的部分,比后切的蚯蚓的对应部分长。。。有可能你会想蚯蚓不是随时在长吗,当然这不影响。。我们来简单证明一下

    ------------------------------------------------证明部分-------------------------------------------------------

    首先第一存初始的蚯蚓,x1>x2,先切x1,切完是x1*p(A部分)和x1-x1*p(B部分),另外一个变长成为x2+q;

    第二个时间点切原来x2这条,切完是(x2+q)*p(A部分)和x2+q-(x2+q)*p(B部分),第一条蚯蚓切后长成x1*p+q和x1-x1*p+q

    然后来对应比较    我们以A部分为例子      x1*p+q  :  (x2+q)*p=x2*p+q*p

    由题意可以知道p的范围是0<p<1,所以x1*p>x2*p,q>q*p进一步得出所以 x1*p+q> (x2+q)*p,同理,切出来的另一半也是这样的。。

    -----------------------------------------------------------------------------------------------------------------

    所以我们只要不断的将新切出来的蚯蚓按A部分和B部分分别压入两个队列,那这两个队列都是单调队列

    每次选择要切的蚯蚓只需要取这三个队列队首的最大值

    第二个要考虑的问题就是蚯蚓长大的问题,为了更好的处理这个细节,我们对每一个蚯蚓对还原成最初状态,即在变长后切割完就减去当前的时间*q。。

    减去以后,三个队列里的蚯蚓都是没有成长的状态,有可能有负数但是不影响。。。

    【细节问题】

    1.首先是数组范围,队列我没试过,但是我数组开10^6是runtime error了。后来开成10^7才通过

    2.接着是用来找最大值的ans,就是用来更新并求最大值的一个变量(详细见代码),这个东东的初值要是10^9以上的,虽然题目说蚯蚓长小于10^8,但是在m秒后长大了

    m*q的长度,这加起来就接近10^8次方了,所以这也是一个细节

    3.还有就是把蚯蚓减回初识形态时,不仅要减去之前时间大家长大的长度,还要额外减去一个,因为被砍的蚯蚓当前这一秒是不会生长,相对于所有就要少一个q,为了保证最后所有的蚯蚓+m*q就是正确值,就要对当前切开的蚯蚓额外减去q

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cstdlib>
     6 #include<cmath>
     7 #include<queue>
     8 #define maxn 100005
     9 #define maxm 700005
    10 #define maxv 10000005
    11 #define inf 2000000005
    12 using namespace std;
    13 
    14 int h[4],t[4],a[maxm];//h->指针,队首......t->队的长度
    15 int b[4][maxv],n,m,q,u,v,tt,del;
    16 
    17 int comp(const void*a,const void*b){
    18     return (*(int*)a)<(*(int*)b)?1:-1;
    19 }
    20 
    21 int main(){
    22     scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&tt);
    23     h[1]=h[2]=h[3]=1;
    24     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    25     a[0]=inf;
    26     qsort(a,n+1,sizeof(int),comp);
    27     for(int i=1;i<=n;i++)b[1][i]=a[i];
    28     t[1]=n;
    29     
    30     for(int i=1;i<=m;i++){
    31         int ans=-inf,num=0;//num表示当前选出队首最大的那个队列序号 
    32         for(int j=1;j<=3;j++){
    33             if(h[j]<=t[j]){//指针不越界 
    34                 if(b[j][h[j]]>ans){
    35                     ans=b[j][h[j]];num=j;//找三个队列的队首最大值 
    36                 }
    37             }
    38         }
    39         if(i%tt==0)printf("%d ",ans+del);
    40         h[num]++;//理解为删除操作 
    41         b[2][++t[2]]=(long long)(ans+del)*u/v-del-q;//队尾压入一个切开的A值
    42         b[3][++t[3]]=ans+del-(long long)(ans+del)*u/v -del-q;//队尾压入一个切开的B值
    43         del+=q;
    44     }
    45     printf("
    ");
    46     for(int i=1;i<=n+m;i++){
    47         int ans=-inf,num=0;
    48         for(int j=1;j<=3;j++){
    49             if(h[j]<=t[j]&&b[j][h[j]]>ans){
    50                 ans=b[j][h[j]];num=j;
    51             }
    52         }
    53         if(i%tt==0){    printf("%d ",ans+del);}
    54         h[num]++;
    55     }
    56     return 0;
    57 } 
    View Code

    【总结】

    1.对于一道题,要分析数据的变化,就像这题中蚯蚓的长度一样,不是始终小于题所给的10^8,所以要分析全局来赋值

    2.数组的大小要严谨分析,在不会爆内存的情况下可以多开,虽然我刚刚开始开的是n+m大小,但是因为不会删去之前的蚯蚓,所以这个大小还不够,还是会越界

    3.很多题是带有结论的,需要去证明,所以不要盲目去做一题,稍加分析,当然也可以先打暴力来辅助分析

  • 相关阅读:
    SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSIS 系列
    微软BI 之SSAS 系列
    微软BI 之SSRS 系列
    微软BI 之SSRS 系列
    配置 SQL Server Email 发送以及 Job 的 Notification通知功能
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7659802.html
Copyright © 2011-2022 走看看