zoukankan      html  css  js  c++  java
  • 【bzoj3203】[Sdoi2013]保护出题人 凸包+二分

    题目描述

    输入

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

    输出

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

    样例输入

    5 2
    3 3
    1 1
    10 8
    4 8
    2 3

    样例输出

    7


    题解

    凸包+二分

    把第 $i$ 只僵尸的血量看作前 $i$ 只僵尸的血量的前缀和,那么就相当于所有僵尸同时受到伤害。

    把僵尸的距离堪称 $x$ ,血量看成 $y$ ,要求的就是 $frac yx$ 的最大值。显然最大值一定在上凸壳上取到,因此维护凸壳,在凸壳上二分即可。

    然而每次加入的僵尸位置是队头,相当于把所有后面僵尸的血量都加上 $a_i$ 。我们不能实现整体加减,因此需要平移原点。调整距离同理。

    时间复杂度 $O(nlog n)$ 

    #include <cstdio>
    typedef long double ld;
    struct point
    {
    	ld x , y;
    	point() {}
    	point(ld a , ld b) {x = a , y = b;}
    }sta[100010] , O(0 , 0) , P;
    int top;
    inline ld slop(point a , point b)
    {
    	return (b.y - a.y) / (b.x - a.x);
    }
    int main()
    {
    	int n , i , l , r , mid , ret;
    	ld a , x = 0 , y , d , ans = 0;
    	scanf("%d%Lf" , &n , &d);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%Lf%Lf" , &a , &y) , P = point(O.x + x - d , O.y);
    		while(top > 1 && slop(P , sta[top]) < slop(P , sta[top - 1])) top -- ;
    		sta[++top] = P;
    		O.x -= y + d - x , O.y -= a;
    		ret = 1 , l = 2 , r = top;
    		while(l <= r)
    		{
    			mid = (l + r) >> 1;
    			if(slop(O , sta[mid]) > slop(O , sta[mid - 1])) ret = mid , l = mid + 1;
    			else r = mid - 1;
    		}
    		ans += slop(O , sta[ret]) , x = y;
    	}
    	printf("%.0Lf
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    MySQL 慢日志没有自动创建新的日志文件
    Springboot为什么加载不上application.yml的配置文件
    android studio set proxy
    c++ win32 遍历进程列表
    React Prompt组件 阻止用户离开页面
    JS 浏览器上生成 UUID API
    部署 Nestjs 最佳实践
    Nginx 部署 单页面应用 + nodejs api 应用 最佳实践
    React JS: 如何使用 RxService 管理状态
    umijs 开发优化和生产优化
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8137127.html
Copyright © 2011-2022 走看看