问题链接 AcWing 105. 七夕祭
问题描述
分析
首先,如果想要做到每行的摊位数都一样,那么总摊位数一定是行数的倍数(0倍也行),同理如果想要做到每列的摊位数都一样,那么总摊位数应该是列数的倍数。
其次,我们可以发现,我们在行上调整某个摊位,不会影响该摊位所在列的摊位数量,比如摊位 x 的位置为(x,y),上下调整到(x+1,y)、(x-1,y)不会影响对这一列的摊位数量有影响,同理我们在列上调整某个摊位,不会影响该摊位所在行的摊位数量。所以我们的目标最小的交换次数就等于最小在行上面的交换次数+最小在列上面的交换次数。这样就把问题拆分了。
可以发现,在行/列上,这是一道环型均分纸牌问题,这样就很好解决了。下面进行数学推导:
(这里分析行,列也是如此): 假设有n行,用集合{
a
1
,
a
2
,
.
.
.
.
,
a
n
a_1,a_2,....,a_n
a1,a2,....,an}表示,每行最终状态=avg=
∑
i
=
1
n
a
i
n
\frac{\sum\limits_{i=1}^{n}a_i}{n}
ni=1∑nai,avg可以直接算出来。那么我们根据上图可得,每个数都能从上一个数获得值,也能将自己的值传递给下一个数,最终达到avg,所以有:
a
1
+
x
2
−
x
1
=
a
v
g
a
2
+
x
3
−
x
2
=
a
v
g
a
3
+
x
4
−
x
3
=
a
v
g
.
.
.
.
.
a
n
−
2
+
x
n
−
1
−
x
n
−
2
=
a
v
g
a
n
−
1
+
x
n
−
x
n
−
1
=
a
v
g
a
n
+
x
1
−
x
n
=
a
v
g
a_1+x_2-x_1=avg\\ a_2+x_3-x_2=avg\\ a_3+x_4-x_3=avg\\ .....\\ a_{n-2}+x_{n-1}-x_{n-2}=avg\\ a_{n-1}+x_{n}-x_{n-1}=avg\\ a_n+x_1-x_n=avg
a1+x2−x1=avga2+x3−x2=avga3+x4−x3=avg.....an−2+xn−1−xn−2=avgan−1+xn−xn−1=avgan+x1−xn=avg
做变形,将
a
i
a_i
ai移到等式右边,可得:
x
2
−
x
1
=
a
v
g
−
a
1
x
3
−
x
2
=
a
v
g
−
a
2
x
4
−
x
3
=
a
v
g
−
a
3
.
.
.
.
.
x
n
−
1
−
x
n
−
2
=
a
v
g
−
a
n
−
2
x
n
−
x
n
−
1
=
a
v
g
−
a
n
−
1
x
1
−
x
n
=
a
v
g
−
a
n
x_2-x_1=avg-a_1\\ x_3-x_2=avg-a_2\\ x_4-x_3=avg-a_3\\ .....\\ x_{n-1}-x_{n-2}=avg-a_{n-2}\\ x_{n}-x_{n-1}=avg-a_{n-1}\\ x_1-x_n=avg-a_n
x2−x1=avg−a1x3−x2=avg−a2x4−x3=avg−a3.....xn−1−xn−2=avg−an−2xn−xn−1=avg−an−1x1−xn=avg−an
从下往上做累加,可得:
x
1
−
x
1
=
n
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
+
a
2
+
a
1
}
=
0
x
1
−
x
2
=
(
n
−
1
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
+
a
2
}
x
1
−
x
3
=
(
n
−
2
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
}
.
.
.
.
.
x
1
−
x
n
−
2
=
3
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
a
n
−
2
}
x
1
−
x
n
−
1
=
2
∗
a
v
g
−
{
a
n
+
a
n
−
1
}
x
1
−
x
n
=
a
v
g
−
a
n
x_1-x_1=n*avg-\{a_n+a_{n-1}+....+a_3+a_2+a_1\}=0\\ x_1-x_2=(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\}\\ x_1-x_3=(n-2)*avg-\{a_n+a_{n-1}+....+a_3\}\\ .....\\ x_{1}-x_{n-2}=3*avg-\{a_n+a_{n-1}+a_{n-2}\}\\ x_{1}-x_{n-1}=2*avg-\{a_n+a_{n-1}\}\\ x_1-x_n=avg-a_n
x1−x1=n∗avg−{an+an−1+....+a3+a2+a1}=0x1−x2=(n−1)∗avg−{an+an−1+....+a3+a2}x1−x3=(n−2)∗avg−{an+an−1+....+a3}.....x1−xn−2=3∗avg−{an+an−1+an−2}x1−xn−1=2∗avg−{an+an−1}x1−xn=avg−an
再次变形,将
x
1
x_1
x1挪到等式右侧:
x
1
=
x
1
−
{
n
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
+
a
2
+
a
1
}
}
=
x
1
−
0
x
2
=
x
1
−
{
(
n
−
1
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
+
a
2
}
}
x
3
=
x
1
−
{
(
n
−
2
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
}
}
.
.
.
.
.
x
n
−
2
=
x
1
−
{
3
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
a
n
−
2
}
}
x
n
−
1
=
x
1
−
{
2
∗
a
v
g
−
{
a
n
+
a
n
−
1
}
}
x
n
=
x
1
−
{
a
v
g
−
a
n
}
x_1=x_1-\{n*avg-\{a_n+a_{n-1}+....+a_3+a_2+a_1\}\}=x_1-0\\ x_2=x_1-\{(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\}\}\\ x_3=x_1-\{(n-2)*avg-\{a_n+a_{n-1}+....+a_3\}\}\\ .....\\ x_{n-2}=x_{1}-\{3*avg-\{a_n+a_{n-1}+a_{n-2}\}\}\\ x_{n-1}=x_{1}-\{2*avg-\{a_n+a_{n-1}\}\}\\ x_n=x_1-\{avg-a_n\}
x1=x1−{n∗avg−{an+an−1+....+a3+a2+a1}}=x1−0x2=x1−{(n−1)∗avg−{an+an−1+....+a3+a2}}x3=x1−{(n−2)∗avg−{an+an−1+....+a3}}.....xn−2=x1−{3∗avg−{an+an−1+an−2}}xn−1=x1−{2∗avg−{an+an−1}}xn=x1−{avg−an}
我们的目标是
min
{
∣
x
1
∣
+
∣
x
2
∣
+
.
.
.
.
+
∣
x
n
∣
}
\min\{|x_1|+|x_2|+....+|x_n|\}
min{∣x1∣+∣x2∣+....+∣xn∣},按照上式子,
可以转化成最小化
min
{
∣
x
1
−
0
∣
+
∣
x
1
−
{
(
n
−
1
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
+
a
2
}
}
∣
}
+
.
.
.
.
+
∣
x
1
−
{
2
∗
a
v
g
−
{
a
n
+
a
n
−
1
}
}
∣
+
∣
x
1
−
{
a
v
g
−
a
n
}
∣
\min\{|x_1-0|+|x1-\{(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\}\}|\}+....+|x_1-\{2*avg-\{a_n+a_{n-1}\}\}|+|x_1-\{avg-a_n\}|
min{∣x1−0∣+∣x1−{(n−1)∗avg−{an+an−1+....+a3+a2}}∣}+....+∣x1−{2∗avg−{an+an−1}}∣+∣x1−{avg−an}∣
这个式子的含义就是
x
1
x_1
x1到点
{
0
,
(
n
−
1
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
+
a
2
}
,
(
n
−
2
)
∗
a
v
g
−
{
a
n
+
a
n
−
1
+
.
.
.
.
+
a
3
}
,
.
.
.
,
2
∗
a
v
g
−
{
a
n
+
a
n
−
1
}
,
a
v
g
−
a
n
}
\{0,(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\},(n-2)*avg-\{a_n+a_{n-1}+....+a_3\},...,2*avg-\{a_n+a_{n-1}\},avg-a_n\}
{0,(n−1)∗avg−{an+an−1+....+a3+a2},(n−2)∗avg−{an+an−1+....+a3},...,2∗avg−{an+an−1},avg−an}的距离,那么这就是一个区间选址的贪心问题,
x
1
x_1
x1的值选在这些点的中间位置即可。
代码如下
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int r[N],c[N];//存原始数据
int c_r[N],c_c[N];
int main(){
int n,m,t;
ll row=-1,column=-1;
cin>>n>>m>>t;
for(int i=0;i<t;i++){
int x,y;
scanf("%d%d",&x,&y);
r[x]++;
c[y]++;
}
int avg;
if(t%n==0){
row=0;
avg=t/n;
int res=0;
for(int i=1;i<=n;i++){
res+=avg-r[n-i+1];
c_r[i]=res;
}
sort(c_r+1,c_r+n+1);
for(int i=1;i<=n;i++)
row+=abs(c_r[(n+1)>>1]-c_r[i]);
}
if(t%m==0){
column=0;
avg=t/m;
int res=0;
for(int i=1;i<=m;i++){
res+=avg-c[m-i+1];
c_c[i]=res;
}
sort(c_c+1,c_c+m+1);
for(int i=1;i<=m;i++)
column+=abs(c_c[(m+1)>>1]-c_c[i]);
}
if(row==-1&&column==-1) puts("impossible");
else if(row>=0&&column>=0) cout<<"both "<<row+column<<endl;
else if(row>=0) cout<<"row "<<row<<endl;
else cout<<"column "<<column<<endl;
return 0;
}