zoukankan      html  css  js  c++  java
  • BZOJ 4614 【WF2016】 Oil

    题目链接:Oil

      感觉同时几线作战有点吃不消啊……

      这道题有一个显然的结论,那就是最优的直线一定过某条线段的端点。

      仔细想想很有道理。如果最终的直线没有过线段的端点的话,那么这条直线就一定可以平移,直到过端点为止。

      于是我们可以枚举直线上的一个点,由于直线不能与线段平行,那么与枚举的点纵坐标不同的线段就对应着一个斜率区间。于是这个问题就转化成了一个经典问题:有$n$个区间,第$i$个区间$[l_i,r_i]$会给区间内的所有位置(可以不是整数)加上一个权值$c_i$,求最后所有位置中最大的权值。这个问题解法很简单,就是把每个区间拆成两个点,然后从左往右扫,扫到左端点就加上权值,扫到右端点就减去权值,取个$max$即可。

      还有一点小优化:枚举点的时候不必枚举所有端点,可以只枚举所有左端点(或者右端点)。因为如果最终的直线不过任何线段的左端点的话,那么一定可往左平移到过一个左端点为止。

      还有计算斜率的时候由于可能会有斜率不存在的情况,可以把斜率式中的$x$、$y$互换一下,方便计算。

      下面贴代码(自带巨大常数):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define N 2010
    #define eps (1e-8)
    
    using namespace std;
    typedef double llg;
    
    struct data{
    	int x,y;
    }l[N],r[N],a[N];
    struct dato{
    	llg l,r;int c;
    }s[N],sl[N],sr[N];
    int n,ans,ls,ld;
    llg d[N<<1];
    
    bool cmpl(dato a,dato b){return a.l<b.l;}
    bool cmpr(dato a,dato b){return a.r<b.r;}
    
    int main(){
    	File("a");
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d %d %d",&l[i].x,&r[i].x,&r[i].y); l[i].y=r[i].y;
    		if(l[i].x>r[i].x) swap(l[i],r[i]); a[i]=l[i];
    		d[++ld]=l[i].x,d[++ld]=r[i].x;
    		ans=max(ans,r[i].x-l[i].x);
    	}
    	for(int i=1,id,now;i<=n;i++){
    		ls=ld=0; id=(i-1)%n+1;
    		for(int j=1;j<=n;j++)
    			if(l[j].y!=a[i].y){
    				ls++; s[ls].c=r[j].x-l[j].x;
    				s[ls].l=(llg)(l[j].x-a[i].x)/(llg)(l[j].y-a[i].y);
    				s[ls].r=(llg)(r[j].x-a[i].x)/(llg)(r[j].y-a[i].y);
    				if(s[ls].l>s[ls].r) swap(s[ls].l,s[ls].r);
    			}
    		if(ls){
    			now=r[id].x-l[id].x;
    			for(int i=1;i<=ls;i++) d[++ld]=s[i].l,d[++ld]=s[i].r,sl[i]=sr[i]=s[i];
    			sort(d+1,d+ld+1); ld=unique(d+1,d+ld+1)-d-1;
    			sort(sl+1,sl+ls+1,cmpl); sort(sr+1,sr+ls+1,cmpr);
    			for(int i=1,zl=1,zr=1;i<=ld;i++){
    				while(zl<=ls && d[i]==sl[zl].l) now+=sl[zl++].c;
    				ans=max(ans,now);
    				while(zr<=ls && d[i]==sr[zr].r) now-=sr[zr++].c;
    			}
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    四则运算
    实验四 决策树算法及应用
    实验三 朴素贝叶斯算法及应用
    实验二 K-近邻算法及应用
    实验三 面向对象分析与设计
    实验二 结构化分析与设计
    实验一 软件开发文档与工具的安装与使用
    ATM管理系统
    流程图与活动图的区别与联系
    四则运算自动生成程序
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6240153.html
Copyright © 2011-2022 走看看