• BZOJ 3203 [SDOI2013]保护出题人 (凸包+三分)


    洛谷传送门

    题目大意:太长略

    每新加入一个僵尸,容易得到方程$ans[i]=max{frac{sum_{i}-sum_{j-1}}{s_{i}+d(i-j)}}$

    即从头开始每一段僵尸都需要在规定距离内被消灭

    展开式子,可得$ans[i]=max{frac{sum_{i}-sum_{j-1}}{s_{i}+di-dj}}$

    是不是很像斜率的式子= = ----$(y2-y1)/(x2-x2)$

    维护一个下凸包,这次不是用直线去切凸包,而是把凸包上每个点都向一个定点去连直线,求最大的斜率

    会发现,凸包上连出来的直线的斜率是一个凸函数,再利用三分法进行查找

    三分法类似于一个爬坡的过程,每次都缩小两侧山坡范围,最终找到山顶

    至于为什么维护下凸包呢,画个图就明白了,如果之前某个点$a$,与点$b(b_{x}<a_{x})$的斜率,大于新加入的点$i$与$b$的斜率,那么如果右侧出现一个点,向他们连直线,显然$i$的斜率大于$a$,可以用三角形的性质去证

    因为$x$递增,用单调栈维护下凸包即可

    时间$O(nlogn)$

    貌似比较斜率必须用$double$,不然爆$long;long$

     1 #include <cmath>
     2 #include <queue>
     3 #include <vector>
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <algorithm>
     7 #define N1 101000
     8 #define M1 205
     9 #define ll long long
    10 #define dd double  
    11 #define uint unsigned int
    12 using namespace std;
    13 
    14 ll gll()
    15 {
    16     ll ret=0;int fh=1;char c=getchar();
    17     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    18     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
    19     return ret*fh;
    20 }
    21 int n;
    22 ll D;
    23 ll a[N1],s[N1],sa[N1];
    24 ll x[N1],y[N1];
    25 int stk[N1],tp;
    26 inline dd gslope(int i,int j){
    27     return 1.0*(y[i]-y[j])/(x[i]-x[j]);
    28 }
    29 
    30 int main()
    31 {
    32     //freopen("t2.in","r",stdin);
    33     scanf("%d%lld",&n,&D);
    34     for(int i=1;i<=n;i++)
    35         a[i]=gll(),s[i]=gll(),sa[i]=sa[i-1]+a[i];
    36     dd ans=0;
    37     for(int i=1;i<=n;i++)
    38     {
    39         x[i]=1.0*i*D,y[i]=sa[i-1];
    40         while(tp>1&&gslope(stk[tp],stk[tp-1])>=gslope(i,stk[tp-1]))
    41             tp--;
    42         stk[++tp]=i;
    43         int l=1,r=tp,mid1,mid2;
    44         x[0]=1.0*s[i]+1.0*D*i,y[0]=sa[i];
    45         while(r-l>=3)
    46         {
    47             mid1=(l+l+r)/3,mid2=(l+r+r)/3;
    48             if(gslope(0,stk[mid1])>gslope(0,stk[mid2]))
    49                 r=mid2;
    50             else 
    51                 l=mid1;
    52         }
    53         dd ma=0;
    54         for(int j=l;j<=r;j++)
    55             ma=max(ma,gslope(0,stk[j]));
    56         ans+=ma;
    57     }
    58     printf("%.0lf
    ",ans);
    59     return 0;
    60 }
  • 相关阅读:
    28.注解2.md
    29.Junit测试框架.md
    WCF学习笔记(2)-WCF的通讯过程
    WCF学习笔记(1)-一个完整的例子
    Sql2008事务日志已满处理
    面向对象六大原则
    计算机基础(1)-原码、反码、补码
    Spring.Net学习笔记(7)-事务
    Spring.Net学习笔记(6)-方法注入
    Spring.Net学习笔记(5)-集合注入
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10053358.html
Copyright © 2020-2023  润新知