zoukankan      html  css  js  c++  java
  • [BZOJ3203] [SDOI2013]保护出题人(二分+凸包)

    [BZOJ3203] [SDOI2013]保护出题人(二分+凸包)

    题面

    题面较长,略

    分析

    对于第i关,我们算出能够打死前k个个僵尸的最小能力值,再取最大值就可以得到(y_i).

    前j-1个僵尸到门的距离为(x_i+(i-j+1) imes d),血量为(sum[i]-sum[j]),因此

    [y_i=max(frac{sum_i-sum_j}{x_i+(i-j+1) imes d})= max(frac{sum_i-sum_j}{x_i+i imes d-(j+1) imes d}) ]

    这个方程没法用一般的斜率优化来转移,但我们注意到除法很像斜率的形式,实际上是((x_i+i imes d,sum_i))(((j+1) imes d,sum_j))之间的斜率

    那么问题就转化成,给出一个定点((x_i+i imes d,sum_i)),求一个点(((j+1) imes d,sum_j)),使得这两点间斜率最大

    显然备选的点应该在一个斜率单调递增凸壳上。那么我们可以像斜率优化那样维护一个凸壳。找斜率最大点显然可以三分,但还有更简单的方法。注意到斜率最大点下方的点到定点的向量,和凸壳上相邻点的向量的叉积为负。我们只要找到x坐标最小,且叉积为正的点即可,直接二分答案。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100000
    #define eps 1e-6
    using namespace std;
    int n;
    double d;
    struct Vector{
    	double x;
    	double y;
    	Vector(){
    		
    	}
    	Vector(double _x,double _y){
    		x=_x;
    		y=_y;
    	}
    	friend Vector operator + (Vector p,Vector q){
    		return Vector(p.x+q.x,p.y+q.y);
    	}
    	friend Vector operator - (Vector p,Vector q){
    		return Vector(p.x-q.x,p.y-q.y);
    	}
    };
    typedef Vector point;
    double cross(Vector p,Vector q){
    	return p.x*q.y-p.y*q.x;
    }
    double slope(point p,point q){
    	return (p.y-q.y)/(p.x-q.x);
    }
    
    double a[maxn+5],x[maxn+5]; 
    double suma[maxn+5];
    point s[maxn+5];
    
    int bin_search(int l,int r,point k){
    	int ans=1;
    	int mid;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(cross(s[mid+1]-s[mid],k-s[mid])<=eps){
    			ans=mid;
    			r=mid-1;
    		}else l=mid+1;
    	}
    	return ans;
    }
    int main(){
    	scanf("%d %lf",&n,&d);
    	for(int i=1;i<=n;i++){
    		 scanf("%lf %lf",&a[i],&x[i]);
    		 suma[i]=suma[i-1]+a[i];
    	}
    	int top=0;
    	double ans=0;
    	s[++top]=point(d,0); //((0+1)*d,suma[0]) 
    	for(int i=1;i<=n;i++){
    		int best=bin_search(1,top,point(x[i]+i*d,suma[i]));//找到斜率最大的点
    		double val=slope(point(x[i]+i*d,suma[i]),s[best]); 
    		ans+=val;
    		point newp=point((i+1)*d,suma[i]);//插入新的可行点
    		while(top>1&&cross(s[top]-s[top-1],newp-s[top-1])<=eps) top--;
    		s[++top]=newp;
    	}
    	printf("%.0f
    ",ans);
    }
    
    
  • 相关阅读:
    SVN 初级教程
    572 node包管理工具
    571 node的events模块
    570 node内置模块fs
    569 node内置模块path
    568 node之JavaScript模块化:exports,module.exports,import,对象的引用赋值,require查找规则,export、import关键字,CommonJS的加载过程,ES Module加载过程
    567 node概述:Node程序传递参数,常见的全局对象,特殊的全局对象
    566 手写37个 原生JavaScript 系列汇总(含promise A+)
    565 手写promise源码
    564 函数的防抖和节流
  • 原文地址:https://www.cnblogs.com/birchtree/p/11376544.html
Copyright © 2011-2022 走看看