zoukankan      html  css  js  c++  java
  • AcWing 105.七夕祭

    题目描述

    七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。

    于是TYVJ今年举办了一次线下七夕祭。

    Vani同学今年成功邀请到了cl同学陪他来共度七夕,于是他们决定去TYVJ七夕祭游玩。

    TYVJ七夕祭和11区的夏祭的形式很像。

    矩形的祭典会场由N排M列共计N×M个摊点组成。

    虽然摊点种类繁多,不过cl只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。

    Vani预先联系了七夕祭的负责人zhq,希望能够通过恰当地布置会场,使得各行中cl感兴趣的摊点数一样多,并且各列中cl感兴趣的摊点数也一样多。

    不过zhq告诉Vani,摊点已经随意布置完毕了,如果想满足cl的要求,唯一的调整方式就是交换两个相邻的摊点。

    两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。

    由于zhq率领的TYVJ开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。

    现在Vani想知道他的两个要求最多能满足多少个。

    在此前提下,至少需要交换多少次摊点。

    输入格式

    第一行包含三个整数N和M和T,T表示cl对多少个摊点感兴趣。

    接下来T行,每行两个整数x, y,表示cl对处在第x行第y列的摊点感兴趣。

    输出格式

    首先输出一个字符串。

    如果能满足Vani的全部两个要求,输出both;

    如果通过调整只能使得各行中cl感兴趣的摊点数一样多,输出row;

    如果只能使各列中cl感兴趣的摊点数一样多,输出column;

    如果均不能满足,输出impossible。

    如果输出的字符串不是impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。

    数据范围

    1≤N,M≤100000
    ,
    0≤T≤min(N∗M,100000)
    ,
    1≤x≤N
    ,
    1≤y≤M

    样例

    输入样例:
    
    2 3 4
    1 3
    2 1
    2 2
    2 3
    输出样例:
    
    row 1
    

    思路在代码里面

    C++ 代码

    #include <bits/stdc++.h>
    using namespace std;
    /**
     首先先考虑不是环的情况下
     那么就是普通的均匀分牌问题
     那么最少次数就是互相给牌
     if(hang[i] < t / n)
     hang[i + 1] -= (t / n - hang[i]), hang[i] += (t / n - hang[i]);
     else
     hang[i + 1] += (hang[i] - t / n), hang[i] -= (hang[i] - t / n);
     (假设hang数组内的值不发生变化,注意不要从0开始,数据是从1开始的,哭了)
     第一种情况下的状态
     hang[1] = hang[1] - (t / n - hang[0]) = hang[1] + hang[0] - t / n;
     第二种情况下的状态
     hang[1] = hang[1] + (hang[0] - t / n) = hang[1] + hang[0] - t / n; 
     
     第一次的移动次数为abs(t / n - hang[0]);
     第二次的移动次数为abs(t / n - hang[1] - hang[0] + t / n);
                       abs(2 * t / n - (hang[1] + hang[0]));
     所以可得第i次移动的次数为abs(i * t / n - sum(hang[i - 1]));
            那么可以拆分成abs((t / n - hang[0]) + (t / n - hang[1]) + ...... + (t / n - hang[i]));
            预先处理将数组变成 t / n - hang[i]
            那么求一个前缀和就可以得到每次移动的步数
    
     如果是环形的话,存在相邻的交换给的话
     肯定不是最优解,最优解肯定只存在于不互相给的情况下
     因为比如a b c d e 是个环 a -> c b -> e,那么实际上
     这肯定不是最优解
     因为可以通过b -> c , a -> e来构造一个更优秀的答案
     所以最优解只存在于不互相给的情况下
     那么就选择一个不交换的点,将其转换成普通的均匀分牌问题
     那么就重新选择出了一个非环的序列
     那么如何选择这个不交换的点
     假设该点为k
     取k为原点
     那么k就变成了基点,那么我们先求出了全部的sum[i]的值
     k ~ n
     sum[k + 1] - sum[k]
     sum[k + 2] - sum[k + 1]
     ....
     过了n之后,因为过了n后,sum[0] + sum[n] - sum[k]
     构成了新的序列的前缀和
     sum[n] + sum[0] - sum[k]
     sum[n] + sum[k] - sum[k]
     
     那么我们要寻找一个合适的k值
     因为sum[n] + sum[0] - sum[k] or sum[k + 1] - sum[k]
     就是一维上的一个求距离的公式
     那么结论就是 取sum[k]的值为sum[1 ~ n]中的中位数
     **/
    typedef long long ll;
    const int MAXN = 100000 + 5;
    int hang[MAXN];
    int lie[MAXN];
    ll hang_sum[MAXN];
    ll lie_sum[MAXN];
    struct NODE
    {
        ll num;
        ll sum;
    };
    bool cmp(const NODE &a, const NODE &b)
    {
        return a.sum < b.sum;
    }
    int n, m, t;
    void Init()
    {
        memset(hang, 0, sizeof(hang));
        memset(lie, 0, sizeof(lie));
        memset(hang_sum, 0, sizeof(hang_sum));
        memset(lie_sum, 0, sizeof(lie_sum));
    }
    void ycl()
    {
        for(int i = 1; i <= n; i ++)
        {
            hang[i] = hang[i] - t / n;
        }
        for(int i = 1; i <= m; i ++)
        {
            lie[i] = lie[i] - t / m;
        }
        hang_sum[0] = hang[0];
        for(int i = 1; i <= n; i ++)
        {
            hang_sum[i] = hang_sum[i - 1] + hang[i];
        }
        lie_sum[0] = lie[0];
        for(int i = 1; i <= m; i ++)
        {
            lie_sum[i] = lie_sum[i - 1] + lie[i];
        }
    }
    pair<ll, ll> hang_acfinds()
    {
        vector<NODE>vec;
        vec.clear();
        for(int i = 1; i <= n; i ++)
            {
                NODE temp;
                temp.num = i;
                temp.sum = hang_sum[i];
                vec.push_back(temp);
            }
        sort(vec.begin(), vec.end(), cmp);
        return {vec[vec.size() / 2].num, vec[vec.size() / 2].sum};
    }
    pair<ll, ll> lie_acfinds()
    {
        vector<NODE>vec;
        vec.clear();
        for(int i = 1; i <= m; i ++)
            {
                NODE temp;
                temp.num = i;
                temp.sum = lie_sum[i];
                vec.push_back(temp);
            }
        sort(vec.begin(), vec.end(), cmp);
        return {vec[vec.size() / 2].num, vec[vec.size() / 2].sum};
    }
    ll result_hang(pair<ll, ll> num)
    {
        ll re = 0;
        for(int i = 1; i <= num.first; i ++)
            re += abs(hang_sum[i] + hang_sum[n] - num.second);
        for(int i = num.first + 1; i <= n; i ++)
            re += abs(hang_sum[i] - num.second);
        return re;
    }
    ll result_lie(pair<ll, ll> num)
    {
        ll re = 0;
        for(int i = 1; i <= num.first; i ++)
            re += abs(lie_sum[i] + lie_sum[m] - num.second);
        for(int i = num.first + 1; i <= m; i ++)
            re += abs(lie_sum[i] - num.second);
        return re;
    }
    int main()
    {
        while(~scanf("%d%d%d", &n, &m, &t))
        {
            Init();
            for(int i = 0; i < t; i ++)
            {
                int a, b;
                scanf("%d%d", &a, &b);
                hang[a] ++;
                lie[b] ++;
            }
            bool flag1, flag2;
            flag1 = flag2 = false;
            ycl();
            ll re1, re2;
            if(t % n == 0)///在行的情况下,t个能被整除,才存在解
            {
                flag1 = true;
                pair<ll, ll>num;
                num = hang_acfinds();
                re1 = result_hang(num);
            }
            if(t % m == 0)
            {
                flag2 = true;
                pair<ll, ll>num;
                num = lie_acfinds();
                re2 = result_lie(num);
            }
            if(flag1 && flag2)
            {
                printf("both %lld
    ",re1 + re2);
            }
            else if(flag1)
            {
                printf("row %lld
    ", re1);
            }
            else if(flag2)
            {
                printf("column %lld
    ", re2);
            }
            else
            {
                printf("impossible
    ");
            }
        }
        return 0;
    }
    
    

  • 相关阅读:
    多线程008如何预防死锁
    多线程003volatile的可见性和禁止指令重排序怎么实现的
    多线程011线程池运行原理及复用原理
    多线程010为什么要使用线程池
    多线程009什么是守护线程
    多线程005创建线程有哪些方式
    多线程007描述一下线程安全活跃态问题,以及竞态条件
    多线程002ThreadLocal有哪些内存泄露问题,如何避免
    关于Tomcat的启动时机(精通Eclipse Web开发P40)
    乱侃~~~
  • 原文地址:https://www.cnblogs.com/qq136155330/p/10486885.html
Copyright © 2011-2022 走看看