BZOJ3032 七夕祭

时间:2023-12-05 09:01:38

https://remmina.github.io/BZPRO/JudgeOnline/3032.html

题目

背景

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

题目描述

TYVJ 七夕祭和11 区的夏祭的形式很像。矩形的祭典会场由N 排M 列共计N×M 个摊点组成。虽然摊点种类繁多,不过cl 只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。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

样例输出1

row 1

样例输入2

3 3 3
1 3
2 2
2 3

样例输出2

both 2

数据范围与约定

对于100% 的数据,1≤N, M≤100000,0≤T≤min(NM, 100000),1≤x≤N,1≤y≤M。

题解

答案是分别统计每行和每列感兴趣的摊位数,然后执行两次均分纸牌(也如“酒交易”),还需要证明只需要考虑数量,不需要关心位置

首先考虑列

1 1 1
  1 1
    1

必要性:如果能均分,那么关心的摊位的数量一定为列数的倍数

充分性:

知道和为列数的倍数了,因此我们只需要搬动一些摊位,并且不考虑先后顺序的情况下一定能均分= =

如果做不到,说明这个位置仅经过左右移动放不下需要的摊位。但如果这样,说明这几行都是满的(否则摊位的数量不是列数的倍数),符合题目的要求,所以一定能做到。

因此和为列数的倍数等价于能经过左右搬动式每列摊位数相等。

同理可证行的情况

由于移动不改变关心的摊位数量,所以两次移动是独立的。

由于是环形,需要考虑每处打开的链的情况,容易推出公式= =

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<iomanip> #define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) (void)0
#endif using namespace std;
typedef long long LL;
typedef pair<LL, LL> pll;
typedef pair<int, int> pii; char ch; int f;
template <class T>
inline void read(T &x) {
x=0; f=1; do ch=getchar(); while(!isdigit(ch) && ch!='-');
if(ch=='-') ch=getchar(),f=-1; while(isdigit(ch)) {x=x*10+ch-'0';
ch=getchar();} x*=f;
}
int n,m,t;
#define MAXN 100007
LL h[MAXN], l[MAXN];
int main() {
read(n); read(m); read(t);
memset(h,0,sizeof h), memset(l, 0, sizeof l);
REP(i,0,t) {
int a,b; read(a); read(b);
h[a-1]++, l[b-1]++;
}
bool ish=!(t%n), isl=!(t%m); if(ish&&isl) printf("both"); else if(ish) printf("row"); else if(isl) printf("column"); else {puts("impossible"); return 0;}
LL ans=0;
if(ish) {
h[0]-=t/n;
REP(i,1,n) {
h[i]=h[i]-t/n+h[i-1];
}
sort(h,h+n);
REP(i,0,n/2) {
ans+=abs(h[n-i-1]-h[i]);
}
}
if(isl) {
l[0]-=t/m;
REP(i,1,m) {
l[i]=l[i]-t/m+l[i-1];
}
sort(l,l+m);
REP(i,0,m/2) {
ans+=abs(l[m-i-1]-l[i]);
}
}
printf(" %lld\n", ans);
return 0;
}