zoukankan      html  css  js  c++  java
  • Luogu P5302 [GXOI/GZOI2019]特技飞行

    一道码量还算中等的三合一,主要还是套路为主(然后我写到一半把代码删了233)

    首先我们很容易看出来不管改不改变航向,所有的交点位置都是确定的

    而交点意味着什么?逆序对!所以我们就不会奇怪数据范围中给出了交点个数的限制了

    因此我们就有一个很naive的想法,直接暴力归并排序找出所有的逆序对,然后运用一下简单的计算几何知识(其实就是求直线交点)来搞出所有交点

    然后下一部分也很清晰了,直接把固定的加分算出来,这个一眼矩阵数点啊,不强制在线的话离线+扫描线+树状数组就做完了啊

    慢着,这矩阵怎么是斜的233,其实没事,我们把所有点都翻转(frac{pi}{4})即可

    还有一点就是求出的交点都是实数,所以一定要离散化

    然后剩下的就是这道题最不套路的地方了,我们假设一共有(cnt)个交点,然后我们人为决定进行(t)次交换航线,因此这部分的贡献就是(acdot t+bcdot (cnt-t)=(a-b)cdot t+bcdot cnt)

    发现是个关于(t)的一次函数,说明我们只要找出(t)最大最小值就可以得出答案

    首先最大值很好求,我们根据交点个数=逆序对个数以及逆序对的定义,很容易发现最多时全部交换即可,因此(t_{max}=cnt)

    然后我们考虑最后的序列是一个排列,而让一个排列有序的最少步数就是排列长度-置换个数

    为什么的?因为每一个置换想要有序至少要交换置换长度-1次(每次只能让一个数归位,最后一次让两个数归位),因此就可以推出上面的式子了

    所以这道题就大致写完了,最后提醒一下各位:调代码时时刻注意存档!(被辣鸡Devcpp把代码格没了的蒟蒻默默发声)

    CODE

    #include<cstdio>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    typedef double DB;
    const int N=1e5+5,M=5e5+5;
    const DB EPS=1e-8;
    struct Point
    {
        DB x,y;
        inline Point(const DB& X=0,const DB& Y=0)
        {
            x=X; y=Y;
        }
    }P,Q;
    inline Point trans(const Point& P)
    {
        return Point(P.x+P.y,P.y-P.x);
    }
    struct line
    {
        int y1,y2;
    }l[N]; int n,a,b,c,x1,x2,k;
    struct data
    {
        int val,id;
    }s[N];
    inline int dcmp(const DB& x)
    {
        if (fabs(x)<EPS) return 0; return x<0?-1:1;
    }
    struct DB_val
    {
        DB val;
        friend bool inline operator < (const DB_val& A,const DB_val& B)
        {
            return dcmp(A.val-B.val)<0;
        }
        friend bool inline operator == (const DB_val& A,const DB_val& B)
        {
            return !dcmp(A.val-B.val);
        }
    };
    struct event
    {
        int opt; DB x,y1,y2; //opt: 1:add line; -1:del line; 0:query point;
    }et[(N<<1)+M]; int cnt,ret,p,q,r,mi,num;
    struct real_event
    {
        int opt,x,y1,y2;
        friend bool operator < (const real_event& A,const real_event& B)
        {
            return A.x<B.x;
        }
    }rt[(N<<1)+M];
    class FileInputOutput
    {
        private:
            static const int S=1<<21;
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            char Fin[S],*A,*B;
        public:
            Tp inline void read(T& x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            #undef tc
    }F;
    namespace Step1 //Find out all intersections
    {
        data tp[N]; Point cp[M];
        inline Point cross(CI p,CI q)
        {
            DB k1=1.0*(l[p].y2-l[p].y1)/(x2-x1),k2=1.0*(l[q].y2-l[q].y1)/(x2-x1);
            DB b1=l[p].y1-k1*x1,b2=l[q].y1-k2*x1,x=(b2-b1)/(k1-k2),y=k1*x+b1; return Point(x,y);
        }
        inline void divide(CI l=1,CI r=n)
        {
            if (l>=r) return; int mid=l+r>>1; divide(l,mid); divide(mid+1,r);
            RI i=l,j=mid+1,k=l; while (i<=mid&&j<=r) if (s[i].val<s[j].val) tp[k++]=s[i++];
            else { for (RI p=i;p<=mid;++p) cp[++cnt]=cross(s[p].id,s[j].id); tp[k++]=s[j++]; }
            while (i<=mid) tp[k++]=s[i++]; while (j<=r) tp[k++]=s[j++]; for (i=l;i<=r;++i) s[i]=tp[i];
        }
        inline void solve(void)
        {
            divide(); for (RI i=1;i<=cnt;++i) cp[i]=trans(cp[i]),et[i]=(event){0,cp[i].x,cp[i].y,0};
            //for (RI i=1;i<=cnt;++i) printf("%.2lf %.2lf
    ",cp[i].x,cp[i].y);
        }
    };
    namespace Step2 //Point in rectangles identify
    {
        DB_val rst[((N<<1)+M)<<1]; int tot;
        class Tree_Array
        {
            private:
                int bit[(N<<1)+M];
                #define lowbit(x) x&-x
            public:
                inline void add(RI x,CI y)
                {
                    for (;x<=tot;x+=lowbit(x)) bit[x]+=y;
                }
                inline int get(RI x,int ret=0)
                {
                    for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
                }
                #undef lowbit
        }BIT;
        inline int find(const DB& x)
        {
            return lower_bound(rst+1,rst+tot+1,(DB_val){x})-rst;
        }
        inline void solve(void)
        {
            RI i; for (i=1;i<=cnt;++i) rst[i].val=et[i].x; sort(rst+1,rst+cnt+1);
            for (tot=unique(rst+1,rst+cnt+1)-rst-1,i=1;i<=cnt;++i) rt[i].x=find(et[i].x);
            for (tot=0,i=1;i<=cnt;++i) rst[++tot].val=et[i].y1,rst[++tot].val=et[i].y2;
            sort(rst+1,rst+tot+1); tot=unique(rst+1,rst+tot+1)-rst-1;
            for (i=1;i<=cnt;++i) rt[i].opt=et[i].opt,rt[i].y1=find(et[i].y1),rt[i].y2=find(et[i].y2);
            for (sort(rt+1,rt+cnt+1),i=1;i<=cnt;++i) switch (rt[i].opt)
            {
                case 0:
                    if (BIT.get(rt[i].y1)) ++ret; break;
                case 1:
                    BIT.add(rt[i].y1,1); BIT.add(rt[i].y2+1,-1); break;
                case -1:
                    BIT.add(rt[i].y1,-1); BIT.add(rt[i].y2+1,1); break;
            }
        }
    };
    namespace Step3 //Actions at intersections
    {
        int cur; bool vis[N];
        inline int findcircle(void)
        {
            for (RI i=1,j;i<=n;++i) if (!vis[j=s[i].id])
            for (vis[j]=1,++cur,j=s[j].id;j!=s[i].id;j=s[j].id)
            vis[j]=1; return num-(n-cur);
        }
    };
    inline void swap(int& x,int& y)
    {
        int t=x; x=y; y=t;
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        F.read(n); F.read(a); F.read(b); F.read(c); F.read(x1); F.read(x2);
        RI i; for (i=1;i<=n;++i) s[i].id=i,F.read(l[i].y1);
        for (i=1;i<=n;++i) F.read(s[i].val),l[i].y2=s[i].val;
        for (Step1::solve(),num=cnt,F.read(k),i=1;i<=k;++i)
        {
            F.read(p); F.read(q); F.read(r); P=trans(Point(p-r,q)); Q=trans(Point(p+r,q));
            et[++cnt]=(event){1,P.x,Q.y,P.y}; et[++cnt]=(event){-1,Q.x+EPS*10,Q.y,P.y};
        }
        Step2::solve(); int ans1=a*num,ans2=ans1; ans2+=(b-a)*Step3::findcircle();
        if (ans1>ans2) swap(ans1,ans2); return printf("%d %d",ans1+c*ret,ans2+c*ret),0;
    }
    
  • 相关阅读:
    Android高级开发第一讲如何在Android应用中避免内存溢出OOM问题
    Windows Phone 31 日谈——第24日:嵌入字体
    Windows Phone 31 日谈——第22日:应用?还是 游戏?
    Windows Phone 7 开发探索笔记6——页面间传值
    Windows Phone 31 日谈——第23日:提供试用版应用程序
    Windows Phone 7 开发探索笔记1——触控操作之Touch
    修改windowsphone7的默认起始页面
    ObjectC 入门(转)
    Windows Phone 7 开发探索笔记9——菜单栏
    Windows Phone 7 开发探索笔记5——页面间导航
  • 原文地址:https://www.cnblogs.com/cjjsb/p/11094020.html
Copyright © 2011-2022 走看看