题目简介

题目描述

七夕节因牛郎织女的传说而被扣上了“情人节”的帽子。于是 TYVJ 今年举办了一次线下七夕祭。Vani 同学今年成功邀请到了 cl 同学陪他来共度七夕,于是他们决定去 TYVJ 七夕祭游玩。

TYVJ七夕祭和11区的夏祭的形式很像。矩形的祭典会场由\(N\)\(M\)列共计\(N\times M\)个摊点组成。虽然摊点种类繁多,不过 cl 只对其中的\(T\)个摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。Vani 预先联系了七夕祭的负责人 zhq,希望能够通过恰当地布置会场,使得各行中 cl 感兴趣的摊点数一样多,并且各列中 cl 感兴趣的摊点数也一样多。

不过 zhq 告诉 Vani,摊点已经布置完毕了,唯一的调整方式就是交换两个相邻的摊点。两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。由于 zhq 率领的 TYVJ 开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。现在 Vani 想知道他的两个要求最多能满足多少个。在此前提下,至少需要交换多少次摊点。

输入

第一行包含三个整数\(N\)\(M\)\(T\)\(T\)表示cl对多少个摊点感兴趣。

接下来\(T\)行,每行两个整数\(x, y\),表示cl对处在第\(x\)行第\(y\)列的摊点感兴趣。

输出

首先输出一个字符串。如果能满足Vani的全部两个要求,输出both;如果通过调整只能使得各行中cl感兴趣的摊点数一样多,输出row;如果只能使各列中cl感兴趣的摊点数一样多,输出column;如果均不能满足,输出impossible

如果输出的字符串不是impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。

输入 #1

2 3 4
1 3
2 1
2 2
2 3

输入 #2

3 3 3
1 3
2 2
2 3

数据范围

\(1\leq N,M\leq 10^5,0\leq T\leq min(N\times M,10^5)\)

数学分析

「NOIP2002 提高组」均分纸牌「BZOJ1045」「HAOI2008」糖果传递非常相像。

判断第一个问题,其实就是两个除法。

很轻松就能看懂:

if(t%n&&t%m){
    cout<<"impossible";
    return 0;
}else if(t%n)cout<<"column ";
else if(t%m)cout<<"row ";
else cout<<"both ";

对于第二个问题,我们很清楚地知道:

  1. 交换左右只能改变每列中cl感兴趣的摊位数;
  2. 交换上下只能改变每行中cl感兴趣的摊位数;

于是这个问题就被拆分成了:

  1. 通过最少次数的左右交换使每列中cl感兴趣的摊点数相同。
  2. 通过最少次数的上下交换使每行中cl感兴趣的摊点数相同。

这就相当于两次糖果传递了.

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
int x[maxn],y[maxn];
int s[maxn];
inline ll myabs(ll x){return x<0?-x:x;}
int main(){
	int n,m,t;
	cin>>n>>m>>t;
	if(t%n&&t%m){
		cout<<"impossible";
		return 0;
	}else if(t%n)cout<<"column ";
	else if(t%m)cout<<"row ";
	else cout<<"both ";
	for(int i=1;i<=t;i++){
		int ix,iy;
		cin>>ix>>iy;
		x[ix]++,y[iy]++;
	}
	ll ans=0;
	if(!(t%n)){
		for(int i=1;i<=n;i++)s[i]=s[i-1]+x[i]-t/n;
		sort(s+1,s+1+n);
		int mid=s[(n+1)>>1];
		for(int i=1;i<=n;i++)ans+=myabs(s[i]-mid);
	}
	if(!(t%m)){
		for(int i=1;i<=m;i++)s[i]=s[i-1]+y[i]-t/m;
		sort(s+1,s+1+m);
		int mid=s[(m+1)>>1];
		for(int i=1;i<=m;i++)ans+=myabs(s[i]-mid);
	}
	cout<<ans;
	return 0;
} 
$$-----END-----$$