问题
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。
于是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
思路
由题可知:对左右两个摊点的交换,只会改变两列的感兴趣的摊点数量;而对上下两个摊点的交换,也只会改变每两行的感兴趣摊点数量。则可以将本问题分为行满足和列满足两个子问题进行讨论:
- 通过最少次数的上下交换使每行中感兴趣的摊点数量一样
- 通过最少次数的左右交换使每列中感兴趣的摊点数量一样
而对于第一个问题,可以统计好每行的感兴趣摊点数量 row[i]
,则即为将 row[1]
–row[M]
都置为 T/M
(每次可将 row[i]
中的一个摊点移动到 row[(i+1)%(M+1)+1]
或者 row[(i-1+M)%(M+1)+1]
)所需要的最少步数,类似于 纸牌均分 问题,可参照其思路,解出问题。
但需要注意,纸牌均分问题第一个元素和最后一个元素不为连通,而本题为连通的,则肯定能找到一个点 k
,使得环状数组row
在k
后断开,断开的刚好能够符合纸牌均分问题的不连通性,则关键是找到 k
的坐标。其断开后的前缀和如下:
索引 | 新的数组(- avg(=T/M)) | 新的前缀和数组(其中S[M]=0) |
---|---|---|
1 | row[k+1] | S[k+1] - S[k] |
2 | row[k+2] | S[k+2] - S[k] |
…… | …… | …… |
M - k | row[M] | S[M] - S[k] |
M - k +1 | row[1] | S[1] + S[M] - S[k] |
…… | …… | …… |
M | row[k] | S[k] + S[M] - S[k] |
注意:上表中S[M]=0
,S
是 row
减去T/M后的前缀和,则最终结果 S[M] = 0
。
则结果为:
则看到上式,可以知道此公式对应 货仓选址 问题,即将 S
排序后 k 取中位数下标时,可得到 ans
。
题解
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int n, m, t;
int col[N], row[N];
int s[N];
int main() {
cin >> n >> m >> t;
bool st1 = false, st2 = false;
long long res1, res2;
int x, y;
int cnt = 0;
for (int i = 0; i < t; ++i) {
scanf("%d%d", &x, &y);
row[x]++;
col[y]++;
cnt++;
}
if (cnt % n == 0) { //总数可否被行数整除
st1 = true;
int avg = cnt / n;
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + row[i] - avg;
sort(s + 1, s + n + 1);
int mid = s[n / 2 + 1];
res1 = 0;
for (int j = 1; j <= n; ++j) res1 += abs(s[j] - mid);
}
if (cnt % m == 0) { //总数可否被列数整除
st2 = true;
int avg = cnt / m;
for (int i = 1; i <= m; ++i) s[i] = s[i - 1] + col[i] - avg;
sort(s + 1, s + m + 1);
int mid = s[m / 2 + 1];
res2 = 0;
for (int j = 1; j <= m; ++j) res2 += abs(s[j] - mid);
}
if (st1 && st2)cout << "both " << res1 + res2 << endl;
else if (st1) cout << "row " << res1 << endl;
else if (st2) cout << "column " << res2 << endl;
else cout << "impossible" << endl;
return 0;
}
标题: | AcWing-105-七夕祭 |
---|---|
链接: | https://www.fightingok.cn/detail/47 |
更新: | 2022-09-18 22:34:14 |
版权: | 本文采用 CC BY-NC-SA 3.0 CN 协议进行许可 |