zoukankan      html  css  js  c++  java
  • 2018.12.27-dtoj-4089-line

    题目描述:

    给定 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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    ReportMachine打印条形码的问题
    性能测试基础知识
    jmeter请求参数中文乱码及无法读取CSV文件解决办法
    soapui学习
    java环境变量和查看安装路径
    python字典中显示中文
    Jmeter做webservices接口测试
    windows 上robot framework 读取sqlite3提示:OperationalError: unable to open database file错误
    c++ 复习练习
    笔记草稿。
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10188229.html
Copyright © 2011-2022 走看看