• bzoj3203【sdoi2013】保护出题人


    题目描述


    输入格式

    第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离。接下来n行每行两个空格隔开的正整数,第i + 1行为Ai和 Xi,分别表示相比上一关在僵尸队列排头增加血量为Ai 点的僵尸,排头僵尸从距离房子Xi米处开始接近。 


    输出格式

    一个数,n关植物攻击力的最小总和 ,保留到整数。

    数据范围及提示

    对于100%的数据, 1≤n≤10^5,1≤d≤10^12,1≤x≤ 10^12,1≤a≤10^12


    • 题解:

      • 需要先分析一个是否合法的判定规则:
      • 由于一只僵尸被杀死后会立刻攻击后面的僵尸,所以只要对于每一个僵尸满足可以杀死即可;
      • 考虑到第$n$关,最小可防御的攻击力$y_{n}$即:$max {  frac{sum_{i}}{x+(i-1)d} }: 1 le i le n $;
      • 所以求出每关最小的$y_{n}$加起来,考虑快速求每关的$y_{n}$;
      • 和题目中的加入顺序搭配一下即:$frac{ sum_{n} - sum_{i-1} }{ x + (n-i)d }$;
      • 即:$frac{sum_{n} - sum{i-1}}{ x + nd - id }: 1 le i le n $;
      • 可以看成定点$P(sum_{n},x+nd)$和点群$S:(sum_{i-1},id)$的斜率最大值;
      • 注意到$S_{n}$一定在$S_{i}:1 le i lt n$的右上方,同时$P$一定在当前$S$的右上方;
      • 所以对$S$维护一个下凸包,凸包上的点和$P$的斜率满足单峰函数;
      • 三分求值;
    •  1 #include<cstdio>
       2 #include<iostream>
       3 #include<cmath>
       4 #define ll long long
       5 using namespace std;
       6 const int N = 100010;
       7 const double eps = 1e-8;
       8 ll n,d,m;
       9 double x,sum[N],ans;
      10 char gc(){
      11     static char *p1,*p2,s[1000000];
      12     if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
      13     return(p1==p2)?EOF:*p1++;
      14 }
      15 ll rd(){
      16     ll x = 0; char c = gc();
      17     while(c<'0'||c>'9') c = gc();
      18     while(c>='0'&&c<='9') x = x * 10 + c - '0',c = gc();
      19     return x;
      20 }
      21 struct point{
      22     double x,y;
      23     point(){}
      24     point(double x,double y):x(x),y(y){}
      25     point operator -(const point &a){return point(x-a.x,y-a.y);}
      26 }ch[N],P,p;
      27 int dcmp(double x){return (fabs(x)<eps)?0:x<0?-1:1;}
      28 double Cro(point a,point b){return a.x*b.y - b.x*a.y;}
      29 double calc(point a){return a.y/a.x;}
      30 int main()
      31 {   //freopen("bzoj3203.in","r",stdin);
      32     //freopen("bzoj3203.out","w",stdout);
      33     n = rd(); d = rd();
      34     for(int i = 1;i <= n;i++){
      35         sum[i] = rd() + sum[i-1]; x = rd();
      36         p = point(d*i,sum[i-1]);
      37         while(m>1&&Cro(ch[m]-ch[m-1],p-ch[m])<=0) m--;
      38         ch[++m] = p;
      39         P = point(x+i*d,sum[i]);
      40         int l = 1,r = m;
      41         while(r-l>=3){
      42             int Len = (r-l)/3,mid1 = l + Len,mid2 = r - Len;
      43             if(dcmp(calc(P-ch[mid1])-calc(P-ch[mid2]))<=0) l = mid1; else r = mid2;
      44         }
      45         double mx = 0;
      46         for(int j = l;j <= r;j++) mx = max(calc(P-ch[j]),mx);
      47         ans += mx;
      48     }
      49     printf("%.0lf
      ",ans);
      50     return 0;
      51 }//by tkys_Austin;
      bzoj3203
  • 相关阅读:
    初识增长黑客Growth Hacker
    OpenCV学习目录(持续更新)
    leetcode算法-回文判断
    leetcode算法-整数反转
    日常撸题技巧【总结】
    hihocoder 题目类型整理
    【hiho】92-93--素数【数论】
    notepad打造成C/C++IDE【Notepad】
    ACM知识点总结【杂】
    Nastya Studies Informatics
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10293369.html
Copyright © 2020-2023  润新知