题解:
这个题目是一个综合性很强的题目,可以类比为环形分纸牌的问题。我们注意到对于每一行上的相邻元素,交换次序后只会影响到每一列的结果,同样的交换每一列上的相邻元素影响的也只是每一行的结果。
所以我们可以把行和列分隔开分别讨论。但是不管对于行还是对于列,我们都需要满足 K % N(M) = 0
不然肯定无法均分到每一行每一列上。
我们可以先在原数组中处理一下,对于每一行每一列的摊点数目,我们都先预处理为A[i] = A[i] - k/m(n)
,这样就相当于要把所有的A[i]都变成零,我们知道对于一般均分纸牌的问题,答案是sum(s[i])
,s[i]为A[i]前缀和,但是这个题目是一个环形。我们仔细想一下不难发现,对于每一行/列, 总会存在一个位置k没有发生交换操作,(可以反证下,如果每行/列都进行了交换,那就会出现有一行/列的摊位数不为0),所以我们就只需要枚举以下k的位置就可以了。
我们假设这个环在k处断开,那么前缀和数组的变化就是每个值减去s[k].
最后得到的结果就是:
a
n
s
=
s
u
m
(
∣
S
[
i
]
−
S
[
k
]
∣
)
ans = sum(|S[i] - S[k]|)
ans=sum(∣S[i]−S[k]∣)
那么问题就变成了,当k取何值是ans最小,不难发现这个就是中位数的问题了,也就是(n + 1) >> 1
。
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn = 1e5 + 19;
int r[maxn] = {0},s[maxn] = {0},c[maxn] = {0};
int n,m,k;
ll rr = 0,cc = 0,ans1 = 0,ans2 = 0;
bool cmd(int x,int y)
{
if(x != y) return x < y;
}
bool calc_row()//走行数
{
memset(s,0,sizeof(s));
if(rr % n) return 0;
for(int i = 1;i <= n;i++) {
r[i] -= rr/n;
s[i] = s[i - 1] + r[i];
}
sort(s + 1,s + 1 + n,cmd);
int k = (n + 1) >> 1;
for(int i = 1;i <= n;i++){
ans1 += abs(s[i] - s[k]);
}
return 1;
}
bool calc_cl()//走列数
{
memset(s,0,sizeof(s));
if(cc % m) return 0;
for(int i = 1;i <= m;i++){
c[i] -= cc/m;
s[i] = s[i - 1] + c[i];
}
sort(s + 1,s + 1 + m,cmd);
int k = (m + 1) >> 1;
for(int i = 1;i <= m;i++){
ans2 += abs(s[i] - s[k]);
}
return 1;
}
int main()
{
cin >> n >> m >> k;
for(int i = 1;i <= k;i++){
int x,y;
cin >> x >> y;
r[x]++;
c[y]++;
rr++;
cc++;
}
bool cnt1 = calc_row(),cnt2 = calc_cl();
if(cnt1 && cnt2){
cout << "both " << ans1 + ans2 << endl;
}
else if(cnt1){
cout << "row " << ans1 << endl;
}
else if(cnt2){
cout << "column " << ans2 << endl;
}
else{
cout << "impossible" << endl;
}
return 0;
}