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\n",ans);
    50     return 0;
    51 }//by tkys_Austin;
    bzoj3203

     

posted @ 2019-01-19 21:37  大米饼  阅读(258)  评论(0编辑  收藏  举报