交换相邻摊点使得
每行感兴趣摊点数相同 row
每列感兴趣摊点数也相同 column
行列感兴趣摊点数都相同 both
行列感兴趣摊点数都不相同 impossible
对样例分析
o o .
. . .
nums%col = 4%3 = 1 所以列肯定无法满足
nums%row = 4%2 = 0 所以行可以通过交换满足
最少交换1次使得num[第一行] = num[第二行]=2
. o . or o . .
o . . . o .
如果对不同行进行交换,则该列的数量不变 num[row[i]]-1 num[row[i+1]]+1
如果对不同列进行交换,则该行的数量不变 num[col[i]]-1 num[col[i+1]]+1
操作数 = 操作行数+操作列数(操作行和操作列相互独立)
min (A+B) = min A+min B
环形均分纸牌 122 糖果传递
n行 + num[n]每行糖果数量
最少操作num[i]-x num[i+1]+x多少次使得num[i]都一样
假设行分别为 row[1] → row[n]
x2
环结构 row[1] ← row[2]
↓x1 ↑x3
row[n]→...→row[3]
如果row[2]给row[1] 2个 则x2=2
如果row[1]给row[2] 2个 则x2=-2
则 总共行操作数=|x1|+...+|xn|
所有糖果平均数avg = Σrow[i]/n
则有row[1]-x1+x2 = avg
row[2]-x2+x3 = avg
...
row[n]-xn+x1 = avg
n个未知数xi n个方程 唯一解
则有x1-x2 = row[1] - avg
x2-x3 = row[2] - avg
...
xn-x1 = row[n] - avg
用x1作为自由变量表示其他变量
x1 = x1-0
x2 = x1-(row[1]-avg)
x3 = x2-(row[2]-avg)=x1-(row[1]-avg)-(row[2]-avg)
...
xn-1 = ... = x1-Σ(row[i]-avg) for i in range[1,n-2]
xn = x1 + row[n] - avg
总共行操作数
=|x1|+...+|xn|
=|x1-c1| + |x1-c2| +...+ |x1-cn|
首尾合并=(|x1-c1|+|x1-cn|)+(|x1-c2|+|x1-cn-1|)+...
绝对值不等式|a|+|b|≥|a+b|
绝对值号内取反|x1-cn| = |cn-x1|
≥|cn-x1+x1-c1| + |c[n-1]-x1+x1-c2| ...
=|cn-c1| + |c[n-1] - c2| + |c[n-2]-c2| + ...|c[n-k]-ck|
|a|+|b|≥|a+b|取等条件a,b同号
即|cn-x1+x1-c1|中cn-x1>=0 x1-c1>=0
即x1 = 所有数的中位数
其中 ci= Σ(row[j]-avg) for j in range[1,i-1]
= s[i-1]-(i-1)*avg
则问题变为找一个点xk 到n个点0,c2,...,cn的距离之和最小
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int row[N], col[N], s[N], c[N];
LL work(int n,int a[])
{
//算糖果数前缀和
for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i];
if (s[n] % n) return -1;
int avg = s[n] / n;
c[1] = 0;
for (int i = 2; i <= n; i ++ ) c[i] = s[i - 1] - (i - 1) * avg;
sort(c + 1, c + n + 1);
LL res = 0;
//x1 = c[i]中的中位数 = c[(n+1)/2]
for (int i = 1; i <= n; i ++ ) res += abs(c[i] - c[(n + 1) / 2]);
return res;
}
int main()
{
int n, m, cnt;
scanf("%d%d%d", &n, &m, &cnt);
while (cnt -- )
{
int x, y;
scanf("%d%d", &x, &y);
row[x] ++, col[y] ++ ;//第x行糖果++ 第y列糖果++
}
LL r = work(n, row);
LL c = work(m, col);
if (r != -1 && c != -1) printf("both %lld\n", r + c);
else if (r != -1) printf("row %lld\n", r);
else if (c != -1) printf("column %lld\n", c);
else printf("impossible\n");
return 0;
}
thx
结构清晰