七夕祭
题目链接
题目描述
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。
于是 T Y V J TYVJ TYVJ 今年举办了一次线下七夕祭。
V a n i Vani Vani 同学今年成功邀请到了 c l cl cl 同学陪他来共度七夕,于是他们决定去 T Y V J TYVJ TYVJ 七夕祭游玩。
T Y V J TYVJ TYVJ 七夕祭和 11 11 11 区的夏祭的形式很像。
矩形的祭典会场由 N N N 排 M M M 列共计 N × M N×M N×M 个摊点组成。
虽然摊点种类繁多,不过 c l cl cl 只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。
V a n i Vani Vani 预先联系了七夕祭的负责人 z h q zhq zhq,希望能够通过恰当地布置会场,使得各行中 c l cl cl 感兴趣的摊点数一样多,并且各列中 cl 感兴趣的摊点数也一样多。
不过 z h q zhq zhq 告诉 V a n i Vani Vani,摊点已经随意布置完毕了,如果想满足 cl 的要求,唯一的调整方式就是交换两个相邻的摊点。
两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。
由于 z h q zhq zhq 率领的 T Y V J TYVJ TYVJ 开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。
现在 V a n i Vani Vani 想知道他的两个要求最多能满足多少个。
在此前提下,至少需要交换多少次摊点。
输入格式
第一行包含三个整数 N N N 和 M M M 和 T T T, T T T 表示 cl 对多少个摊点感兴趣。
接下来 T T T 行,每行两个整数 x , y x,y x,y,表示 cl 对处在第 x x x 行第 y y y 列的摊点感兴趣。
输出格式
首先输出一个字符串。
如果能满足 V a n i Vani Vani 的全部两个要求,输出 b o t h both both;
如果通过调整只能使得各行中 cl 感兴趣的摊点数一样多,输出 r o w row row;
如果只能使各列中 c l cl cl 感兴趣的摊点数一样多,输出 c o l u m n column column;
如果均不能满足,输出 i m p o s s i b l e impossible impossible。
如果输出的字符串不是 i m p o s s i b l e impossible impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。
数据范围
1 ≤ N , M ≤ 100000 , 0 ≤ T ≤ m i n ( N ∗ M , 100000 ) , 1 ≤ x ≤ N , 1 ≤ y ≤ M 1≤N,M≤100000,\\ 0≤T≤min(N∗M,100000),\\ 1≤x≤N,\\ 1≤y≤M 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
思路
由于交换同一列相邻两行的摊位只会改变相关行的“感兴趣摊点数”,交换同一行相邻两列的摊位只会改变相关列的“感兴趣摊点数”,所以可以将问题分成“各列相邻两行的交换”和“各行相邻两列的交换”两部分来解。
以“各行相邻两列的交换”为例。
设 a i a_i ai 为每一列的“感兴趣摊点数”,其中 1 ≤ i ≤ m 1 \le i \le m 1≤i≤m ,若问题有解,那么交换完成后,每个 a i ′ a'_i ai′ 一定都是相等的,即 t t t 可以被 m m m 整除。这样问题就变成了“均分纸牌”问题。
最优的结果一定是只与右侧(或左侧)的摊位交换的。
设
x
i
x_i
xi 为第
i
i
i 列与 第
i
−
1
i-1
i−1 列交换的次数(可以为负),
a
ˉ
=
i
∗
t
m
\bar{a}=i*\frac{t}{m}
aˉ=i∗mt,那么我们有:
x
1
=
x
1
x
2
=
a
2
+
x
1
−
a
ˉ
x
3
=
a
3
+
x
2
−
a
ˉ
x
4
=
a
4
+
x
3
−
a
ˉ
x
i
=
a
i
+
x
i
−
1
−
a
ˉ
x_1=x_1\\ x_2=a_2+x_1-\bar{a}\\ x_3=a_3+x_2-\bar{a}\\ x_4=a_4+x_3-\bar{a}\\ x_i=a_i+x_{i-1}-\bar{a}
x1=x1x2=a2+x1−aˉx3=a3+x2−aˉx4=a4+x3−aˉxi=ai+xi−1−aˉ
如果把所有式子都用
x
1
x_1
x1 来表示,则有:
x
1
=
x
1
−
0
x
2
=
x
1
−
(
a
ˉ
−
a
2
)
x
3
=
x
1
−
(
2
×
a
ˉ
−
a
2
−
a
3
)
x
4
=
x
1
−
(
3
×
a
ˉ
−
a
2
−
a
3
−
a
4
)
x
i
=
x
1
−
(
i
×
a
ˉ
−
∑
j
=
1
i
a
i
)
x_1=x_1-0\\ x_2=x_1-(\bar{a}-a_2)\\ x_3=x_1-(2 \times \bar{a}-a_2-a_3)\\ x_4=x_1-(3 \times \bar{a}-a_2-a_3-a_4)\\ x_i=x_1-(i\times \bar{a}-\sum_{j=1}^i a_i)
x1=x1−0x2=x1−(aˉ−a2)x3=x1−(2×aˉ−a2−a3)x4=x1−(3×aˉ−a2−a3−a4)xi=x1−(i×aˉ−j=1∑iai)
于是问题就变成了,求一个最优的 x k x_k xk,使得 ∑ i = 1 n ∣ x k − ( i × a ˉ − ∑ j = 1 i a i ) ∣ \sum_{i=1}^n |x_k-(i\times \bar{a}-\sum_{j=1}^i a_i)| ∑i=1n∣xk−(i×aˉ−∑j=1iai)∣ 最小。这实际上就是“货仓选址”问题,其中 ∣ x k − ( i × a ˉ − ∑ j = 1 i a i ) ∣ |x_k-(i\times \bar{a}-\sum_{j=1}^i a_i)| ∣xk−(i×aˉ−∑j=1iai)∣ 就相当于“货仓选址”问题中每个货仓的地址。很显然,只有 x k x_k xk 为所有 x i x_i xi 的中位数时,问题的答案才有最小值,详情请见。
由于:
x
k
=
∑
i
=
1
n
∣
x
k
−
(
i
×
a
ˉ
−
∑
j
=
1
i
a
i
)
∣
x_k=\sum_{i=1}^n |x_k-(i\times \bar{a}-\sum_{j=1}^i a_i)|
xk=i=1∑n∣xk−(i×aˉ−j=1∑iai)∣
所以答案的式子还可以表示成:
∑
i
=
1
n
∣
(
i
×
a
ˉ
−
∑
j
=
1
k
a
j
)
−
(
i
×
a
ˉ
−
∑
j
=
1
i
a
i
)
∣
\sum_{i=1}^n |(i\times \bar{a}-\sum_{j=1}^k a_j)-(i\times \bar{a}-\sum_{j=1}^i a_i)|
i=1∑n∣(i×aˉ−j=1∑kaj)−(i×aˉ−j=1∑iai)∣
若设
s
i
=
i
×
a
ˉ
−
∑
j
=
1
i
a
i
s_i=i\times \bar{a}-\sum_{j=1}^i a_i
si=i×aˉ−∑j=1iai,那么最后答案的式子就变成了:
∑
i
=
1
n
∣
s
k
−
s
i
∣
\sum_{i=1}^n |s_k-s_i|
i=1∑n∣sk−si∣
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
long long n,m,t,x,y;
long long row[100001],col[100001];
long long solve(long long a[100001],long long x)
{
int f[100001],s[100001],ans,k;
for(int i=1;i<=x;i++)
{
f[i]=a[i]-t/x;
s[i]=s[i-1]+f[i];
}
sort(s+1,s+x+1);
if(n&1)//求中位数
k=(x+1)/2;
else
k=x/2;
ans=0;
for(int i=1;i<=x;i++)
ans+=abs(s[i]-s[k]);
return ans;
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&t);
for(int i=1;i<=t;i++)
{
scanf("%lld%lld",&x,&y);
row[x]++,col[y]++;
}
if(t%n==0&&t%m==0)
printf("both %lld",solve(row,n)+solve(col,m));
else if(t%m==0)
printf("column %lld",solve(col,m));
else if(t%n==0)
printf("row %lld",solve(row,n));
else
printf("impossible");
return 0;
}