题目描述
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。
于是TYVJ今年举办了一次线下七夕祭。
Vani同学今年成功邀请到了cl同学陪他来共度七夕,于是他们决定去TYVJ七夕祭游玩。
TYVJ七夕祭和11区的夏祭的形式很像。
矩形的祭典会场由N排M列共计N×M个摊点组成。
虽然摊点种类繁多,不过cl只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。
Vani预先联系了七夕祭的负责人zhq,希望能够通过恰当地布置会场,使得各行中cl感兴趣的摊点数一样多,并且各列中cl感兴趣的摊点数也一样多。
不过zhq告诉Vani,摊点已经随意布置完毕了,如果想满足cl的要求,唯一的调整方式就是交换两个相邻的摊点。
两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。
由于zhq率领的TYVJ开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。
现在Vani想知道他的两个要求最多能满足多少个。
在此前提下,至少需要交换多少次摊点。
输入格式
第一行包含三个整数N和M和T,T表示cl对多少个摊点感兴趣。
接下来T行,每行两个整数x, y,表示cl对处在第x行第y列的摊点感兴趣。
输出格式
首先输出一个字符串。
如果能满足Vani的全部两个要求,输出both;
如果通过调整只能使得各行中cl感兴趣的摊点数一样多,输出row;
如果只能使各列中cl感兴趣的摊点数一样多,输出column;
如果均不能满足,输出impossible。
如果输出的字符串不是impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。
数据范围
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
思路在代码里面
C++ 代码
#include <bits/stdc++.h>
using namespace std;
/**
首先先考虑不是环的情况下
那么就是普通的均匀分牌问题
那么最少次数就是互相给牌
if(hang[i] < t / n)
hang[i + 1] -= (t / n - hang[i]), hang[i] += (t / n - hang[i]);
else
hang[i + 1] += (hang[i] - t / n), hang[i] -= (hang[i] - t / n);
(假设hang数组内的值不发生变化,注意不要从0开始,数据是从1开始的,哭了)
第一种情况下的状态
hang[1] = hang[1] - (t / n - hang[0]) = hang[1] + hang[0] - t / n;
第二种情况下的状态
hang[1] = hang[1] + (hang[0] - t / n) = hang[1] + hang[0] - t / n;
第一次的移动次数为abs(t / n - hang[0]);
第二次的移动次数为abs(t / n - hang[1] - hang[0] + t / n);
abs(2 * t / n - (hang[1] + hang[0]));
所以可得第i次移动的次数为abs(i * t / n - sum(hang[i - 1]));
那么可以拆分成abs((t / n - hang[0]) + (t / n - hang[1]) + ...... + (t / n - hang[i]));
预先处理将数组变成 t / n - hang[i]
那么求一个前缀和就可以得到每次移动的步数
如果是环形的话,存在相邻的交换给的话
肯定不是最优解,最优解肯定只存在于不互相给的情况下
因为比如a b c d e 是个环 a -> c b -> e,那么实际上
这肯定不是最优解
因为可以通过b -> c , a -> e来构造一个更优秀的答案
所以最优解只存在于不互相给的情况下
那么就选择一个不交换的点,将其转换成普通的均匀分牌问题
那么就重新选择出了一个非环的序列
那么如何选择这个不交换的点
假设该点为k
取k为原点
那么k就变成了基点,那么我们先求出了全部的sum[i]的值
k ~ n
sum[k + 1] - sum[k]
sum[k + 2] - sum[k + 1]
....
过了n之后,因为过了n后,sum[0] + sum[n] - sum[k]
构成了新的序列的前缀和
sum[n] + sum[0] - sum[k]
sum[n] + sum[k] - sum[k]
那么我们要寻找一个合适的k值
因为sum[n] + sum[0] - sum[k] or sum[k + 1] - sum[k]
就是一维上的一个求距离的公式
那么结论就是 取sum[k]的值为sum[1 ~ n]中的中位数
**/
typedef long long ll;
const int MAXN = 100000 + 5;
int hang[MAXN];
int lie[MAXN];
ll hang_sum[MAXN];
ll lie_sum[MAXN];
struct NODE
{
ll num;
ll sum;
};
bool cmp(const NODE &a, const NODE &b)
{
return a.sum < b.sum;
}
int n, m, t;
void Init()
{
memset(hang, 0, sizeof(hang));
memset(lie, 0, sizeof(lie));
memset(hang_sum, 0, sizeof(hang_sum));
memset(lie_sum, 0, sizeof(lie_sum));
}
void ycl()
{
for(int i = 1; i <= n; i ++)
{
hang[i] = hang[i] - t / n;
}
for(int i = 1; i <= m; i ++)
{
lie[i] = lie[i] - t / m;
}
hang_sum[0] = hang[0];
for(int i = 1; i <= n; i ++)
{
hang_sum[i] = hang_sum[i - 1] + hang[i];
}
lie_sum[0] = lie[0];
for(int i = 1; i <= m; i ++)
{
lie_sum[i] = lie_sum[i - 1] + lie[i];
}
}
pair<ll, ll> hang_acfinds()
{
vector<NODE>vec;
vec.clear();
for(int i = 1; i <= n; i ++)
{
NODE temp;
temp.num = i;
temp.sum = hang_sum[i];
vec.push_back(temp);
}
sort(vec.begin(), vec.end(), cmp);
return {vec[vec.size() / 2].num, vec[vec.size() / 2].sum};
}
pair<ll, ll> lie_acfinds()
{
vector<NODE>vec;
vec.clear();
for(int i = 1; i <= m; i ++)
{
NODE temp;
temp.num = i;
temp.sum = lie_sum[i];
vec.push_back(temp);
}
sort(vec.begin(), vec.end(), cmp);
return {vec[vec.size() / 2].num, vec[vec.size() / 2].sum};
}
ll result_hang(pair<ll, ll> num)
{
ll re = 0;
for(int i = 1; i <= num.first; i ++)
re += abs(hang_sum[i] + hang_sum[n] - num.second);
for(int i = num.first + 1; i <= n; i ++)
re += abs(hang_sum[i] - num.second);
return re;
}
ll result_lie(pair<ll, ll> num)
{
ll re = 0;
for(int i = 1; i <= num.first; i ++)
re += abs(lie_sum[i] + lie_sum[m] - num.second);
for(int i = num.first + 1; i <= m; i ++)
re += abs(lie_sum[i] - num.second);
return re;
}
int main()
{
while(~scanf("%d%d%d", &n, &m, &t))
{
Init();
for(int i = 0; i < t; i ++)
{
int a, b;
scanf("%d%d", &a, &b);
hang[a] ++;
lie[b] ++;
}
bool flag1, flag2;
flag1 = flag2 = false;
ycl();
ll re1, re2;
if(t % n == 0)///在行的情况下,t个能被整除,才存在解
{
flag1 = true;
pair<ll, ll>num;
num = hang_acfinds();
re1 = result_hang(num);
}
if(t % m == 0)
{
flag2 = true;
pair<ll, ll>num;
num = lie_acfinds();
re2 = result_lie(num);
}
if(flag1 && flag2)
{
printf("both %lld
",re1 + re2);
}
else if(flag1)
{
printf("row %lld
", re1);
}
else if(flag2)
{
printf("column %lld
", re2);
}
else
{
printf("impossible
");
}
}
return 0;
}