您的位置:首页 > 其它

[bzoj3203][Sdoi2013]保护出题人

2016-02-08 15:40 495 查看
  人生第一道三分?。。。

  把进攻序列里的前i只僵尸看成一个点,横坐标是第i只僵尸到达的时间,纵坐标是这i只僵尸的血量总和。。就是说植物必须在这段时间内输出这些伤害。。那么单位时间的输出伤害就是斜率了。

  问题就变成了对于若干个点,求从原点到各个点斜率的最大值。

  因为D是固定的,而每次新加入僵尸实际就是把原来的点平移。。并且相对位置关系不变。。。所以显然斜率最大的点一定在凸包上= =

  每次就新加入一个点并维护凸包,然后三分找出凸包上的点与原点连线斜率的最大值(原点与凸包上各个点连线的斜率是单峰的)就好了。。

  数据范围有点吓人。。。但事实上double就够了。。。判断浮点数大小的时候也不用写eps= =

#include<iostream>
#include<cstdio>
#include<cstring>
#define d double
#define ll long long
using namespace std;
const int maxn=100233;

ll hp[maxn],tr[maxn];
int dl[maxn],l,r;
ll n,m,D,dis;
int i,j,k;
d ans;

ll ra;char rx;
inline ll read(){
rx=getchar(),ra=0;
while(rx<'0'||rx>'9')rx=getchar();
while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
}

inline void add(int x,ll v){for(;x<=n;x+=x&(-x))tr[x]+=v;}
inline ll query(int x){
ll tmp=0;
for(;x;x-=x&(-x))tmp+=tr[x];
return tmp;
}
inline d prexl(int x){
return (d)query(x)/(d)(dis+D*(x-i));
}//原点出发的斜率
inline d disxl(int a,int b){
return (d)(query(b)-query(a))/(d)(D*(b-a));
}//两点间斜率
inline d get(int l,int r){
int l1,r1;
while(l+2<r){
l1=l+(r-l+1)/3,r1=r-(l1-l);
if(prexl(dl[l1])<=prexl(dl[r1]))l=l1;else r=r1;
}
for(l1=l+1,r1=dl[l];l1<=r;l1++)if(prexl(dl[l1])>prexl(r1))r1=dl[l1];
return prexl(r1);
}

int main(){
n=read(),D=read();
l=n+1,r=n;
for(i=n;i;i--){
hp[i]=read(),add(i,hp[i]),dis=read();//printf("    %lld %lld\n",hp[i],dis);
//        for(j=i;j<=n;j++)printf("  %lld",query(j));puts("");
while(l<r&& disxl(i,dl[l])<=disxl(dl[l],dl[l+1]) )l++;
dl[--l]=i;
ans+=get(l,r);
}
printf("%.0lf\n",ans);
return 0;
}


View Code

写完这题B站排名就233啦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: