• [51nod1457]小K vs. 竹子


      小K的花园种着n颗竹子(竹子是一种茎部中空并且长得又高又快的热带植物)。此时,花园中第i颗竹子的高度是hi米,并且在每天结束的时候它生长ai米。

      实际上,小K十分讨厌这些竹子。他曾经试图去砍光它们,但由于竹子的茎部太坚固而失败了,然而,小K制作了魔法锤使这些竹子只能在地面上生长。

      由于魔法力量有限,他每天最多能使用K次魔法锤。每次他使用魔法锤敲击竹子,竹子的高度就会减少p米。通过这次改变,如果竹子的高度变为负数,那它转而会变为0米(但它不会消失)。换言之,如果一颗被魔法锤敲击的竹子的高度是h,那它的新高度将会是max(0, h - p)米。我们可以在一天中多次敲击同一颗竹子。

      小K将会从今天开始和这些竹子抗战m天。他的目标是在m天后使其中最高的竹子的高度最小化(即,“小K敲击竹子,然后竹子生长”的m次迭代)。找出m天后,最高的竹子的高度的最小可能值。

     Input
      输入的第一行包含四个以空格隔开的整数n,m,k和p(1 ≤ n ≤ 10^5 ,1 ≤ m ≤ 5000, 1 ≤k≤ 10, 1 ≤ p ≤ 10^9)。它们分别表示小K 花园中的竹子数,小K抗战的持续天数,每天小K能敲击竹子的最多次数和魔法锤的力量。
      接下来n行描述了竹子的特性,第i行(1 ≤ i ≤ n) 包含两个以空格隔开的整数hi和ai,(0 ≤ hi ≤ 10^9, 1 ≤ ai ≤ 10^9),分别表示第i颗竹子的初始高度和生长速率。
     Output
      输出m天后,最高的竹子的高度的最小可能值。

      跑去看了cf官网的题解。。

      先二分,判定是否可行的时候可以时光倒流。假设最后所有竹子的高度都是二分的答案mid,倒着过去每天,竹子就会变矮p米,不能让竹子的高度变成负数,魔法锤变成给竹子加高度。最后只要使所有竹子高度>=实际初始高度就好了。

      每次用魔法锤的时候,如果存在竹子再过一些天高度就变负数的话,就用在变负天数最少的竹子上。不然就用在最后和实际初始高度差最大的竹子上。用个堆维护一下。

      复杂度两个log

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cmath>
     7 #include<cstdlib>
     8 #define ll long long
     9 #define ull unsigned long long
    10 #define ui unsigned int
    11 #define d double
    12 #define ld long double
    13 const int maxn=100233;
    14 
    15 struct zs{int id;ll h,tim;};std::priority_queue<zs>q;
    16 struct zsa{ll h,v;}a[maxn];
    17 int i,j,k,n,m,kk,p;
    18 
    19 int ra,fh;char rx;
    20 inline int read(){
    21     rx=getchar(),ra=0,fh=1;
    22     while(rx<'0'&&rx!='-')rx=getchar();
    23     if(rx=='-')fh=-1,rx=getchar();
    24     while(rx>='0')ra=ra*10+rx-48,rx=getchar();return ra*fh;
    25 }
    26 
    27 bool operator <(zs a,zs b){return a.tim>b.tim;}
    28 inline bool check(ll X){
    29     register int i;int tim;zs now;
    30     while(!q.empty())
    31         q.pop();
    32     //printf("mid:%lld
    ",X);
    33     for(i=1;i<=n;i++)if(X<a[i].v*m+a[i].h)
    34         q.push((zs){i,X,X/a[i].v+1});//,printf("   %d
    ",i);
    35     for(i=1;i<=kk*m&&!q.empty();i++){
    36         tim=(i+kk-1)/kk,
    37         now=q.top(),q.pop();
    38         if(now.tim<=tim)return 0;
    39         now.h+=p,now.tim=now.h/a[now.id].v+1;
    40         if(now.h<a[now.id].v*m+a[now.id].h)q.push(now);
    41     }
    42     return q.empty();
    43 }
    44 inline ll max(ll a,ll b){return a>b?a:b;}
    45 int main(){
    46     n=read(),m=read(),kk=read(),p=read();
    47     ll l=1,r=0,mid;
    48     for(i=1;i<=n;i++)a[i].h=read(),a[i].v=read(),r=max(r,a[i].h+m*a[i].v);
    49     
    50     while(l<r){//printf("   %lld %lld
    ",l,r);
    51         if(check(mid=l+r>>1))r=mid;else l=mid+1;
    52     }
    53     printf("%lld
    ",l);
    54 }
    View Code
  • 相关阅读:
    0112centos上面l安装卸载mysq
    0111mysql如何选择Join的顺序
    0111MySQL优化的奇技淫巧之STRAIGHT_JOIN
    0108MySQL集群搭建详解(三种结点分离)
    0106主从复制
    0104探究MySQL优化器对索引和JOIN顺序的选择
    MongoDB整理笔记の新增Shard Server
    MongoDB整理笔记の管理Sharding
    MongoDB整理笔记のSharding分片
    MongoDB整理笔记の减少节点
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5950922.html
Copyright © 2020-2023  润新知