zoukankan      html  css  js  c++  java
  • BZOJ4614 [Wf2016]Oil

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

     

    本文作者:ljh2000 

    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

     

     

    Description

    给定n条平行线段,每条线段的价值是它的长度。现在用一条直线贯穿最大价值的线段,求最大的价值。
    N<=2000。
     

    Input

    第一行一个数n表示线段数。家下来n行每行三个数x0,x1和y,表示线段(x0,y)-(x1,y)。
    |x0|,|x1|<=10^6,1<=y<=10^6。线段无交。

    Output

    输出最大的价值。

    Sample Input

    1
    -100 180 20

    Sample Output

    280

    正解:结论+搜索

    解题报告:

      这道题很有意思,我开始也没想到那个结论。

      这道题有一个很有用的结论:最优解的直线必然是经过了某一条线段的端点。仔细想想就会发现其实很有道理,或者说显然?

      这样就很方便了,因为$n$只有$2000$,所以 $n^2$ 暴力即可。我不妨枚举一个端点,作为直线必然经过的那个端点,那么对于经过这个端点的直线,如果我想经过别的线段,显然可以通过作出别的线段的两个端点到这个点的斜率来得到一个可行的范围。假如直线斜率在这个范围内,这条线段就会产生贡献。我们得到了一个可行的做法:得到所有线段关于这个点的斜率得到若干个区间,之后扫一遍即可知道在什么时候能取到最大值了。但是有一些需要注意的地方:斜率有可能不存在,而且可能接近无限大。考虑到直线不能平行于线段,即斜率不能为$0$,我们不妨用斜率的倒数来维护上述操作,很容易发现,对于这道题来说,会减少很多计算而且方便很多,精度误差也小很多。

    //It is made by ljh2000
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int MAXN = 2011;
    const double eps = 1e-8;
    int n,ans,tot;
    struct node{int x0,x1,y,len;}a[MAXN];
    struct seq{double k;int type;}b[MAXN*2];
    inline bool cmp(seq q,seq qq){ return q.k<qq.k; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void solve(double x,double y){
    	int cnt=0;
    	for(int i=1;i<=n;i++) {
    		if(a[i].y==y) continue;
    		b[++cnt].k=(a[i].x0-x)/(a[i].y-y); 
    		b[++cnt].k=(a[i].x1-x)/(a[i].y-y);
    		if(b[cnt].k>b[cnt-1].k) {
    			b[cnt-1].type=a[i].len;
    			b[cnt].type=-a[i].len;
    			b[cnt].k+=eps;
    		}
    		else{
    			b[cnt-1].type=-a[i].len;
    			b[cnt].type=a[i].len;
    			b[cnt-1].k+=eps;
    		}
    	}
    	sort(b+1,b+cnt+1,cmp);
    	for(int i=1;i<=cnt;i++) {
    		tot+=b[i].type;
    		if(tot>ans) ans=tot;
    	}
    }
    
    inline void work(){
    	n=getint(); ans=0;
    	for(int i=1;i<=n;i++) {
    		a[i].x0=getint(),a[i].x1=getint(),a[i].y=getint();
    		if(a[i].x0>a[i].x1) swap(a[i].x0,a[i].x1);
    		a[i].len=a[i].x1-a[i].x0;
    	}
    	for(int i=1;i<=n;i++) {
    		tot=a[i].len; if(tot>ans) ans=tot;
    		solve(a[i].x0,a[i].y);
    		tot=a[i].len;
    		solve(a[i].x1,a[i].y);
    	}
    	printf("%d",ans);
    }
    
    int main()
    {
        work();
        return 0;
    }
    

      

  • 相关阅读:
    linux操作提示:“Can't open file for writing”或“operation not permitted”的解决办法
    CSS中background:url(图片) 不能显示的问题
    CSS3background-size背景图片尺寸属性
    在GitHub上成果预览
    快速上手GitHub上传代码
    css布局模型(1)
    css+div浮动怎么让它在窗口大小变化时不改变位置
    node.js基于express框架搭建一个简单的注册登录Web功能
    node.js 安装使用http-server
    grunt安装与运行
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6238435.html
Copyright © 2011-2022 走看看