题目
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。
于是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
【题解】:想法有点受环形纸牌启发。
1.这题的横竖行是不会相互影响的,可以看成两边去计算。用t(要摆的摊位数)分别去和n,m取余,如果可以整除就存在满足的情况。
2.最小的移动数分开来求。结论是从中位数开始移动结果最小。
证明:
把每数的需求算出来以后,从接口处(0的地方)求前缀和sum,假设从k开始移动,那么移动次数为|sum【1】-sum【k】|+|sum【2】-sum【k】|+|sum【3】-sum【k】|+…可以知道当sum【k】是中位数的时候整个结果最小,所以排序之后取就好了。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100004;
int hang[maxn],lie[maxn];
int sumh[maxn],suml[maxn];
int main()
{
int n,m,t;
cin>>n>>m>>t;
if(t==0)
{
cout<<"both "<<0<<endl;
return 0;
}
for(int i=0;i<t;i++)
{
int a,b;
cin>>a>>b;
hang[a]++;
lie[b]++;
}
int hp=t/n;
int lp=t/m;
sumh[0]=hang[0]-hp;
suml[0]=lie[0]-lp;
for(int i=1;i<n;i++)
{
sumh[i]=(sumh[i-1]+(hang[i]-hp));
}
sort(sumh,sumh+n);
for(int i=1;i<m;i++)
{
suml[i]=(suml[i-1]+(lie[i]-lp));
}
sort(suml,suml+m);
ll ans=0;
if(t%n==0&&t%m==0)
{
for(int i=0;i<n;i++)
{
ans+=1ll*abs(sumh[i]-sumh[n/2]);
}
for(int i=0;i<m;i++)
{
ans+=1ll*abs(suml[i]-suml[m/2]);
}
cout<<"both "<<ans<<endl;
}
else if(t%n==0)
{
for(int i=0;i<n;i++)
{
ans+=1ll*abs(sumh[i]-sumh[n/2]);
}
cout<<"row "<<ans<<endl;
}
else if(t%m==0)
{
for(int i=0;i<m;i++)
{
ans+=1ll*abs(suml[i]-suml[m/2]);
}
cout<<"column "<<ans<<endl;
}
else
{
cout<<"impossible"<<endl;
}
return 0;
}