码迷,mamicode.com
首页 > 其他好文 > 详细

2018.12.27-dtoj-4089-line

时间:2018-12-28 00:53:46      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:分享   char   play   define   namespace   ons   none   图片   lib   

题目描述:

给定 n ?元组 [li.ri] ,求有多少整数序列 a ?1 i n,li ai ri {(i,ai)|1 i n} 在平?上形成了?条直线。

算法标签:半平面交

思路:

容易得到式子,li<=a1+(i-1)*d<=ri,把两个式子拆开看成为一个拥有2*n条直线的半平面交,于是我们的任务变成求围成的凸多边形内所拥有的整点个数。

考虑这是一个由至多2*n条直线构成的凸多边形,上下范围在某个区间内被相同两条直线所限制,在这段区间内所能形成的整点数,是一个等比数列可以o1求出,于是只有处理出区间,就可以得到整点个数,效率O(n)。

注意!!因为d的范围可以达到负数,所以在转式子的过程中,正负影响不等式符号,导致我们要分两半计算。

以下代码:

技术分享图片
#include<bits/stdc++.h>
#define il inline
#define LL long long
#define db double 
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5,inf=1e9;
int n,l[N],r[N],mn=inf,mx,q1[N],tot1,q2[N],tot2;LL ans=0;db j[N],j2[N];
il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
il db gj(db k1,db b1,db k2,db b2){return (b1-b2)/(k2-k1);}
il LL gs(int L,int len,int d){return (LL)L*len+(LL)len*(len-1)/2*d;}
il void work(){
    tot1=tot2=0;
    for(int i=n;i;i--){
        while(tot1>1&&gj(-i,l[i],-q1[tot1-1],l[q1[tot1-1]])<j[tot1])tot1--;
        j[1+tot1]=gj(-i,l[i],-q1[tot1],l[q1[tot1]]);q1[++tot1]=i;
    }
    for(int i=1;i<=n;i++){
        while(tot2>1&&gj(-i,r[i],-q2[tot2-1],r[q2[tot2-1]])<j2[tot2])tot2--;
        j2[tot2+1]=gj(-i,r[i],-q2[tot2],r[q2[tot2]]);q2[++tot2]=i;
    }
    j[tot1+1]=j2[tot2+1]=inf;int t1=1,t2=1;
    for(int la=1;;){
        while(t1<tot1&&j[t1+1]<la)t1++;while(t2<tot2&&j2[t2+1]<la)t2++;
        db p=(q1[t1]!=q2[t2]?gj(-q1[t1],l[q1[t1]],-q2[t2],r[q2[t2]]):inf);
        int R=min(min((int)j[t1+1],(int)j2[t2+1]),(p<la?inf:(int)p));
        if(-la*q2[t2]+r[q2[t2]]+la*q1[t1]-l[q1[t1]]+1<=0){
            if(q1[t1]<q2[t2])break;
            la=(p<la?R:(p-(int)p!=0?p+1:(int)p));continue;
        }
        ans+=gs(-la*q2[t2]+r[q2[t2]]-l[q1[t1]]+la*q1[t1]+1,R-la+1,-(q2[t2]-q1[t1]));
        la=R+1;
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)l[i]=read(),r[i]=read(),mn=min(mn,r[i]),mx=max(mx,l[i]);
    ans=max(0,mn-mx+1);work();
    for(int i=1;i<=n;i++){int t=l[i];l[i]=-r[i];r[i]=-t;}
    work();printf("%lld\n",ans);
    return 0;
}
View Code

 

2018.12.27-dtoj-4089-line

标签:分享   char   play   define   namespace   ons   none   图片   lib   

原文地址:https://www.cnblogs.com/Jessie-/p/10188229.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!