zoukankan      html  css  js  c++  java
  • 七夕祭【模拟】

    题目大意:

    有一个会场由NM列共计N×M个摊点组成。但是小L只对其中的一部分摊点感兴趣。他预先联系了会场的负责人,希望能够通过恰当地布置会场,使得各行中他感兴趣的摊点数一样多,并且各列中他感兴趣的摊点数也一样多。
    但是摊点已经随意布置完毕了,如果想满足小L的要求,唯一的调整方式就是交换两个相邻的摊点。两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上,每一行或每一列的第一个位置和最后一个位置也算作相邻。现在小L想知道他的两个要求最多能满足多少个。在此前提下,至少需要交换多少次摊点。
    Input

    2 3 4
    1 3
    2 1
    2 2
    2 3

    Output

    row 1

    思路:

    如果这道题只有一行,且一行的最后和第一不相连的话,就很容易想到 均分纸牌 。所以说,这道题其实就是均分纸牌的进阶版。
    但是这道题并不能贪心。毕竟O(N2)还是吃不消的。
    如果使用均分纸牌的方法,那么就枚举从第k个位置开始,像均分纸牌的方法一样依次向后推。最后取最小值。预计得分 70 分。

    #include <cstdio>
    using namespace std;
    int n,a[101],mid,sum,x;
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            mid+=a[i];  //求n个数的总和 
        } 
        mid/=n;  //算平均值 
        for (int i=1;i<=n;i++)
        {
            if (a[i]!=mid)  //如果a[i]不等于mid 
            {
                sum++;  //移动次数加1 
                x=a[i]-mid;  //假设a[i]比mid大x(x可以为负数) 
                a[i+1]+=x; 
            }
        }
        printf("%d\n",sum);
        return 0;
    }

    其实洛谷上还有另外一道题很像这道题。糖果传递,跟这道题就真的很像了。
    可以利用前缀和的思想,求出每一行的感兴趣摊点的个数,将这些前缀和排序,再求出中位数,按照|s1sk|+|s2sk|+|s3sk|++|snsk|公式求出答案即可。
    那么为什么选择中位数就一定对呢?
    我们把这个问题看成一条路上有m户人家,要在这条路上打一口井,问选择哪里打井可以使所有人家到达井的总路程最小?
    这里写图片描述
    不难发现,水井有无限个位置可以放,但是肯定是放2号人加到4号人家之间最优。那么在那个点是在最优中最优呢?
    这里写图片描述
    无论水井放在2号人家和4号人家之间的那个点,3号人家外的所有点到达水井的距离都是不变的。那么问题就转化成了:水井放在哪里距离3号人家最近?
    那这个问题就很明显了:放在3号人家的门口肯定离3号人家最近嘛!
    所以说,无论有3,5,7...2x+1个人家,只要放在最中间(中位数)的人家就一定满足最优。
    那么当人家为偶数个呢?
    这里写图片描述
    这里写图片描述
    那么,只要水井放在中间两户人家(3号人家和4号人家)之间,答案都最优。
    所以,如果这道题选择中位数,那么一定能保证答案最优。


    代码:

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    long long h[100001],l[100001],x,y,n,m,k,sum,s1[100001],s2[100001],z1,z2;
    
    void H()  //计算行
    {
        for (int i=1;i<=n;i++)
         s1[i]=s1[i-1]+h[i]-z1;  //前缀和
        sort(s1+1,s1+1+n);  //排序
        int mid=s1[(n+1)/2];  //中位数
        for (int i=1;i<=n;i++)
         sum+=abs(s1[i]-mid);  //公式
    }
    
    void L()  //计算列
    {
        for (int i=1;i<=m;i++)
         s2[i]=s2[i-1]+l[i]-z2;
        sort(s2+1,s2+1+m);
        int mid=s2[(m+1)/2];
        for (int i=1;i<=m;i++)
         sum+=abs(s2[i]-mid);
    }
    
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        z1=k/n;
        z2=k/m;
        for (int i=1;i<=k;i++)
        {
            scanf("%lld%lld",&x,&y);
            h[x]++;
            l[y]++;
        }
        if ((!(k%n))&&(!(k%m)))  //both情况
        {
            printf("both ");
            H();
            L();
        }
        else if (!(k%n))  //row情况
        {
            printf("row ");
            H();
        }
        else if (!(k%m))  //column情况
        {
            printf("column ");
            L();
        }
        else return printf("impossible")&0;
        return printf("%lld\n",sum)&0;
    }
  • 相关阅读:
    XML中对于一个books.xml的详情显示,删除按钮,修改并保存按钮 和 添加按钮。完成这些按钮所对应的功能(XmlDocument)。
    如何写一个验证码
    Binary Search
    数据库排行榜
    mac os 下 sublime text 2 和 iterm2 便捷配置
    HttpGet,HttpPost,HttpPut,HttpDelete
    Compile C/C++ In Eclipse for Android
    To Use EGit(Git for Eclipse)
    Android NDK about Library (static library , share library and 3rd party library)
    Dealing with bitmap object in android NDK
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/9313030.html
Copyright © 2011-2022 走看看