题意:
有一个n*m的矩阵上面是n * m个摊位,给定T个cl感兴趣的摊位的坐标,问现在能否使每行或每列上cl感兴趣的摊位个数相等,可以交换相邻两个摊位的位置每行或每列的头和尾也属于相邻。
思路:
因为行列之间不能交换所以行列的判断是分开的,当总的感兴趣摊位数目不能均分到每一行或每一列时,则行的方案或列的方案不可行。单独看行和列的方案,如果可行那么每行上的感兴趣摊位数量等于总的感兴趣摊位数量/行数,是一个定值,那么我们可以遍历每一行如果当前行没有达到定值就去下一行拿(下一行可以被拿成负值,下一行可以去找再下一行拿,反正最终每行都是定值,就是要看怎么才能是最小交换次数这就需要用到中位数了)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int H[maxn],Z[maxn],f[maxn];
ll cal(int a[],int n) {
ll ans = 0;
for(int i=1;i<=n;i++) {
a[i] -= a[0]/n;
f[i] = f[i-1]+a[i];
}
sort(f+1,f+1+n);
for(int i=1;i<=n;i++) {
ans+=abs(f[i]-f[(n+1)>>1]);
}
return ans;
}
int main()
{
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=k;i++) {
int x,y;
cin>>x>>y;
H[x]++;Z[y]++;
}
for(int i=1;i<=n;i++) {
H[0] += H[i];
}
for(int i=1;i<=m;i++) {
Z[0] += Z[i];
}
if(H[0]%n==0&&Z[0]%m==0) {
printf("both %lld\n", cal(H, n) + cal(Z, m));
} else if(H[0]%n == 0) {
printf("row %lld\n", cal(H, n) );
} else if(Z[0]%m == 0) {
printf("column %lld\n", cal(Z, m));
} else {
cout<<"impossible"<<endl;
}
return 0;
}