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, 接下来输出最小交换次数,与字符串之间用一个空格隔开。

数据范围

1N,M1000001≤N,M≤100000,
0Tmin(NM,100000)0≤T≤min(N∗M,100000),
1xN1≤x≤N,
1yM1≤y≤M

输入样例:

2 3 4
1 3
2 1
2 2
2 3

输出样例:

row 1

算法:前缀和 + 中位数 + 分治 + 贪心

注意:因为行交换和列交换互补影响,所以可以分为两部分来计算。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long ll;

ll a[100005], b[100005];
ll sum[100005];

ll solve(ll c[], int n) {
    int aver = c[0] / n;
    for(int i = 1; i <= n; i++) {
        sum[i] = sum[i - 1] + c[i] - aver;      //sum[i]代表c[i]变好需要几次
    }
    sort(sum + 1, sum + n + 1);
    int mid = (n + 1) >> 1;
    ll ans = 0;
    for(int i = 1; i <= n; i++) {
        ans += abs(sum[mid] - sum[i]);
    }
    return ans;
}

int main() {
    int n, m, t;
    scanf("%d %d %d", &n, &m, &t);
    for(int i = 1; i <= t; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        a[x]++;
        b[y]++;
        a[0]++;
        b[0]++;
    }
    int sa = a[0] % n, sb = b[0] % m;
    if(!sa && !sb) {
        cout << "both " << solve(a, n) + solve(b, m);
    } else if(!sa) {
        cout << "row " << solve(a, n);
    } else if(!sb) {
        cout << "column " << solve(b, m);
    } else {
        cout << "impossible" << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/buhuiflydepig/p/11285791.html