AcWing 七夕祭

AcWing 七夕祭

Description

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

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

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

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

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

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

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

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

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

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

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

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

Input

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

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

Output

  • 首先输出一个字符串。

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

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

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

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

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

Data Size

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

Sample Input

2 3 4
1 3
2 1
2 2
2 3

Sample Output

row 1

题解:

  • 数学题(中位数) + 贪心
  • 嘛少见的锻炼思维的好题QAQ
  • 首先发现交换两行的摊点不会影响到两列;交换两列的摊点不会影响到两行
  • 所以行和列是独立的,故可以分别处理,问题就转换成了:
  1. 通过最少次数使每行中的兴趣摊点一样多
  2. 通过最少次数使每列中的兴趣摊点一样多
  • 进一步思考,如果T % n != 0,说明不能使每行的兴趣摊点一样多;相同的,如果T % m != 0,说明不能使每列的兴趣摊点一样多。那么如果T % n == 0 或者 T % m == 0的情况怎么办呢?
  • 接下来以行为例(列同理):
  • 先考虑没有环的情况:
  • 因为最终每行的兴趣摊点个数是T / n(平均数),所以一开始就让原数组减掉这个平均数,那么就要通过交换位置,使得数组上每一个位置的值为0即符合题意。
  • 假如减掉平均数后c[1] = 3,代表着1这个位置的摊点比平均数多3。那么ans += 3, c[2] += c[1], c[1] = 0,这样写表示将1位置多出来的3个摊点挪到2位置去。假如c[2] = -1,那么加上c[1]后就变成了2,那么ans += 2, c[3] += c[2], c[2] = 0,以此类推。最终ans既为所求
  • 可以推出,ans = \(\sum|C[i]|, (1<= i <= N);C[i] = \sum A[j], (1<= j <= i)\)
  • A为初始数组减掉平均数后的数组,C为A的前缀和
  • 上面的运算过程实际上是“均分纸牌”这题的思路。
  • 你可能会问:不是每次只能交换两个摊点吗?怎么你一下把3个摊点都挪动了。
  • 因为最终的时候1位置肯定要挪动3次,每次都是挪到2位置。那么计算就不用一次一次算,直接一次性算既可。
  • 那么,有环怎么办呢?
  • 一种暴力的想法就是断环成链,找最优的。但复杂度就要炸裂。
  • 假设我们在第k个人之后,第k + 1个人之前断环,那么这N个位置的状态就是:
  • A[k + 1] ----- C[k + 1] - C[k]
  • A[k + 2] ----- C[k + 2] - C[k]
  • ... ...
  • A[N] ----- C[N] - C[k]
  • A[1] ----- C[N] - C[k] + C[1]
  • ... ...
  • A[k] ----- C[N] - C[k] + C[k]
  • 因为C[N]等于0(最终每个位置都为0)
  • 所以按照上面推出来的ans公式,可以得到:
  • \(ans = \sum|C[i] - C[k]|, (1 <= i <= N)\)
  • 这个东西像什么?中位数!几何意义就是一堆点到一个定点的几何距离之和。要使距离之和最小,那么那个定点就是一堆点中的中位点啊!
  • 所以先求出初始数组减掉平均数后的数组A,再通过A求出前缀和数组C,然后找到C中的中位数,既可得到ans。对于列的情况同理!
  • 总结一下我们的思考过程:本题 -> 均分纸牌 -> 环形均分纸牌 -> 数学分析 -> 中位数 -> 求解
  • 这种模型转换的思想十分的令人激动,需要反复反复来捣鼓这道题
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define N 100005
#define LL long long 
using namespace std;

LL n, m, T, flag;
LL a[N], b[N], c[N];

LL do1()
{
    LL ans = 0, k;
    if(n % 2) k = (LL)(n / 2) + 1;
    else k = n / 2;
    for(LL i = 1; i <= n; i++) c[i] = c[i - 1] + (a[i] - T / n);
    sort(c + 1, c + 1 + n); //别漏了排序 
    for(LL i = 1; i <= n; i++) ans += abs(c[i] - c[k]);
    return ans;
}

LL do2()
{
    LL ans = 0, k;
    if(n % 2) k = (LL)(m / 2) + 1;
    else k = m / 2;
    for(LL i = 1; i <= m; i++) c[i] = c[i - 1] + (b[i] - T / m);
    sort(c + 1, c + 1 + m); //别漏了排序 
    for(LL i = 1; i <= m; i++) ans += abs(c[i] - c[k]);
    return ans;
}

int main()
{
    cin >> n >> m >> T;
    for(LL i = 1; i <= T; i++)
    {
        LL x, y;
        scanf("%lld%lld", &x, &y);
        a[x]++, b[y]++;
    }
    if(T % n == 0 && T % m == 0) cout << "both " << do1() + do2();
    else if(T % n == 0) cout << "row " << do1();
    else if(T % m == 0) cout << "column " << do2();
    else cout << "impossible";
    return 0;
}

转载于:https://www.cnblogs.com/BigYellowDog/p/11270896.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值