zoukankan      html  css  js  c++  java
  • [bzoj3210]花神的浇花集会

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    在花老师的指导下,每周4都有一个集会活动,俗称“浇水”活动。

    具体浇水活动详情请见BZOJ3153

    但这不是重点

    花神出了好多题,每道题都有两个参考系数:代码难度和算法难度

    花神为了准备浇花集会的题,必须找一道尽量适合所有人的题

    现在花神知道每个人的代码能力x和算法能力y,一道题(代码难度X算法难度Y)对这个人的不适合度为    Max ( abs ( X – x ) , abs ( Y – y ) )

    也就是说无论太难还是太简单都会导致题目不适合做(如果全按花神本人能力设题,绝对的全场爆0的节奏,太简单,则体现不出花神的实力)

    当然不是每次都如花神所愿,不一定有一道题适合所有人,所以要使所有人的不合适度总和尽可能低

    花神出了100001*100001道题,每道题的代码难度和算法难度都为0,1,2,3,……,100000

    n,xi,yi<=10^5   0.1s

    求一个点,使得它到所有点的切尔雪夫距离之和最小

    因为切尔雪夫距离等于把所有点(xi,yi)变成(xi+yi,yi-xi)之后的曼哈顿距离的一半,所以两个坐标求一个中位数就行了。如果中位数奇偶性不同可以暴力一下。

    当然,很容易发现这是一个单峰函数,所以可以爬山

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define getchar() ((S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T))?EOF:*S++)
    #define MN 100000
    char B[1<<15],*S=B,*T=B;
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    struct P{int x,y;}p[MN+5];
    bool cmpx(P x,P y){return x.x<y.x;}
    bool cmpy(P x,P y){return x.y<y.y;}
    int n;
    long long ans=0;
    inline int abs(int x){return x<0?-x:x;}
    inline long long calc(int x,int y)
    {
        long long sum=0;
        for(register int i=1;i<=n;++i) sum+=abs(p[i].x-x)+abs(p[i].y-y);
        return sum;    
    }
    int main()
    {
        n=read();int m=(n+1)>>1,x,y;
        for(register int i=1;i<=n;++i)
        {
            int x=read(),y=read();
            p[i]=(P){x+y,y-x};    
        }
        nth_element(p+1,p+m,p+n+1,cmpx);x=p[m].x;
        nth_element(p+1,p+m,p+n+1,cmpy);y=p[m].y; 
        if((x&1)==(y&1)) return 0*printf("%lld",calc(x,y)>>1);
        else
        {
            ans=(1LL<<60);
            for(register int i=-1;i<=1;i+=2)
                ans=min(ans,min(calc(x+i,y),calc(x,y+i)));
        }
        printf("%lld
    ",ans>>1);
        return 0;
    }
    正解
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define MN 100000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n;ll ans=0;
    const int dis[8][2]={{1,0},{0,1},{0,-1},{-1,0},{1,1},{-1,-1},{-1,1},{1,-1}};
    struct P{int x,y;}p[MN+5];
    bool cmpx(P x,P y){return x.x<y.x;}
    bool cmpy(P x,P y){return x.y<y.y;}
    inline int abs(int x){return x<0?-x:x;}
    inline ll calc(int x,int y)
    {
        if(x<0||y<0||x>MN||y>MN) return (1LL<<60);
        ll sum=0;
        for(int i=1;i<=n;++i) sum+=max(abs(p[i].x-x),abs(p[i].y-y));
        return sum;
    }
    
    int main()
    {
        n=read();int m=(n+1)>>1,x,y;
        for(int i=1;i<=n;++i) p[i].x=read(),p[i].y=read();    
        nth_element(p+1,p+m,p+n+1,cmpx);x=p[m].x;
        nth_element(p+1,p+m,p+n+1,cmpy);y=p[m].y;
        ans=calc(x,y);
        for(int l=5000;l;l>>=1)
        {
            for(int flag=1;flag;)
            {
                flag=0;
                for(int i=0;i<8;++i)
                {
                    int nx=x+dis[i][0]*l,ny=y+dis[i][1]*l;
                    ll now=calc(nx,ny);
                    if(now<ans)
                    {
                        x=nx;y=ny;ans=now;
                        flag=1;
                        break;    
                    }
                }
            }    
        }
        printf("%lld
    ",ans);
        return 0;
    }
    爬山
  • 相关阅读:
    求树中两个节点的最低公共祖先
    [2014校招笔试]判断单链表是否有环?
    二叉树的遍历
    求所有划分集合
    用rand5()生成rand(n)
    由等概率生成的0和1构建rand()函数
    等概率生成0和1
    求输出和为n的所有连续自然数序列
    求正整数n的所有因子
    css 2D转换总结
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3210.html
Copyright © 2011-2022 走看看