zoukankan      html  css  js  c++  java
  • BZOJ3203 [Sdoi2013] 保护出题人

    @(BZOJ)[凸包, 三分法]

    Description

    Description

    Input

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

    Output

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

    Sample Input

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

    Sample Output

    7
    

    HINT

    第一关:距离房子3米处有一只血量3点的僵尸,植物最小攻击力为1.00000; 第二关:距离房子1米处有一只血量1点的僵尸、3米处有血量3点的僵尸,植物最小攻击力为1.33333; 第三关:距离房子8米处有一只血量10点的僵尸、10米处有血量1点的僵尸、12米处有血量3点的僵尸,植物最小攻击力为1.25000; 第四关:距离房子8米处有一只血量4点的僵尸、10米处有血量10点的僵尸、12米处有血量1点的僵尸、14米处有血量3点的僵尸,植物最小攻击力为1.40000; 第五关:距离房子3米处有一只血量2点的僵尸、5米处有血量4点的僵尸、7米处有 血量10点的僵尸、9米处有血量1点的僵尸、11米处有血量3点的僵尸,植物最小攻击力 为2.28571。 植物攻击力的最小总和为7.26905。
    对于100%的数据, 1≤n≤10^5,1≤d≤10^12,1≤x≤ 10^12,1≤a≤10^12

    Solution

    (sum_i = sum_{i - 1} + a_i), 則有對於第(i)次攻擊, 有$$f_i ge max left( frac{sum_i - sum_{j - 1}}{x_i + d * (i - j)} ight)(1 le j le i)$$
    維護一個斜率單調遞增的凸包, 每個點的坐標為((i*d,sum_{i-1})). 對於每一個(i)用三分法找到凸包中與當前點((x_i + i * d, sum_i))的連線斜率最大的點即可.
    注意在整數上三分的方法

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define eps 1e-6
    #define LL long long
    #define mid1 l+(r-l)/3
    #define mid2 l+(r-l)/3*2
    
    const int N=100010;
    
    int n,siz;
    double ans,d,sum[N],xi[N];
    
    struct Point
    {
    	double x,y;
    } q[N];
    
    Point operator - (Point x,Point y)
    {
    	return (Point)
    	{
    		x.x-y.x, x.y-y.y
    	};
    }
    
    inline double Cross(Point x,Point y)
    {
    	return x.x*y.y-x.y*y.x;
    }
    
    inline double calc(Point x)
    {
    	int l=1,r=siz,i;
    	double maxn=0,k1,k2;
    	
    	while(l+2<r)
    		{
    			k1=(x.y-q[mid1].y)/(x.x-q[mid1].x);
    			k2=(x.y-q[mid2].y)/(x.x-q[mid2].x);
    			maxn=max(maxn,max(k1,k2));
    			if(k1<k2) 
    				l=mid1;
    			else 
    				r=mid2;
    		}
    		
    	for(i=l; i<=r; ++i) 
    		maxn=max(maxn,(x.y-q[i].y)/(x.x-q[i].x));
    	return maxn;
    }
    
    int main()
    {
    	int i,j;
    	scanf("%d%lfd",&n,&d);
    	
    	for(i=1; i<=n; ++i)
    		{
    			scanf("%lf%lf",&sum[i],&xi[i]);
    			sum[i]+=sum[i-1];
    		}
    		
    	ans=sum[1]/xi[1];
    	q[siz=1]=(Point)
    	{
    		d,sum[0]
    	};
    	
    	for(i=2; i<=n; ++i)
    		{
    			Point x=(Point)
    			{
    				i*d,sum[i-1]
    			};
    			
    			while(siz>=2&&Cross(q[siz]-q[siz-1], x-q[siz-1])<=0) 
    				--siz;
    				
    			q[++siz]=x;
    			x=(Point)
    			{
    				xi[i]+i*d, sum[i]
    			};
    			ans+=calc(x);
    		}
    		
    	printf("%.0f
    ",ans);
    }
    
  • 相关阅读:
    Caffe学习系列(16):caffe的整体流程
    caffe_windows安装
    r-cnn学习系列(三):从r-cnn到faster r-cnn
    Spatial pyramid pooling (SPP)-net (空间金字塔池化)笔记(转)
    r-cnn学习(二)
    r-cnn学习(一)
    Caffe学习系列(13):对训练好的模型进行fine-tune
    注解
    MATLAB实现回归分析
    MATLAB进行假设检验
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6427241.html
Copyright © 2011-2022 走看看