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 ", ans); return 0; }