问题 M: 七夕祭
时间限制: 1 Sec 内存限制: 128 MB
提交: 75 解决: 20
[提交] [状态] [讨论版] [命题人:admin]
题目描述
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。于是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, 接下来输出最小交换次数,与字符串之间用一 个空格隔开。
样例输入
2 3 4 1 3 2 1 2 2 2 3
样例输出
row 1
提示
对于30%的数据,N,M≤100。
对于70%的数据,N,M≤1000。
对于100%的数据,1≤N,M≤100000,0≤T≤min(NM,100000),1≤x≤N,1≤y≤M。
分析:这个题是均分纸牌,分金币的升级版。下面以分金币问题引入。
一、分金币:
1、题意:圆桌旁坐着n个人,每人有一定数量的金币,金币总数总能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数相等,你的任务是求出被转手的金币数量的最小值。
2、已知每个人初始情况下手中的金币数,那么总金币数MZ=X1+X2+X3+....+XN。最终每个人获得的金币就是M=MZ/N。
3、设整个交换过程中第n个人给第n-1个人共An枚金币,对于n=1时为第一人给第n个人金币数。
4、可得
x1-A1+A2=M; => A1=x1+A2-M;
x2-A2+A3=M; => A2=x2+A3-M;
x3-A3+A4=M; => A3=x3+A4-M;
x4-A4+A1=M; => A4=x4+A1-M;
5、X2=X1-(M-A1);
X3=X2-(M-A2);
X4=X3-(M-A3);
X5=X4-(M-A4);
6、设
x2=x1-C1;
x3=x1-C2;
x4=X1-C3;
被转手的金币数量:ans=|x1|+|x2|+|x3|+|x4|........+|xn|=|x1-0|+|x1-C1|+|x1-C2|.....+|x1-Cn-1|。
(看不懂的,可以从4开始自己往6推一下)
7、问题就是就一个ans的最小值,就可以看作,一共n个点,找到一个点到其它各个点的距离之和最小,经典的货仓选址问题。
X1为C数组的中位数时ans最小。到这里就搞定了。
二、七夕祭
1、impossible的情况很简单,就是行数、列数都不是T的因数。
2、对于行和列互不影响,分开求,就是两个分金币问题。
3、如果n是T的因数,m也是T的因数,那么就是both。
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#define INF 0x3f3f3f3f
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e5+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
#define gcd(a,b) __gcd(a,b)
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
int n,m,t;
int row[MAX],col[MAX];
ll ans;
void solve_row()
{
ll b[MAX],ave=0,mid;
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)
ave+=row[i];
ave/=n;
for(int i=1;i<=n;i++)
row[i]-=ave;
for(int i=1;i<=n;i++)
b[i]=b[i-1]+row[i];
sort(b+1,b+1+n);
mid=b[(n+1)/2];
for(int i=1;i<=n;i++)
ans+=abs(b[i]-mid);
}
void solve_col()
{
ll b[MAX],ave=0,mid;
memset(b,0,sizeof(b));
for(int i=1;i<=m;i++)
ave+=col[i];
ave/=m;
for(int i=1;i<=m;i++)
col[i]-=ave;
for(int i=1;i<=m;i++)
b[i]=b[i-1]+col[i];
sort(b+1,b+1+m);
mid=b[(m+1)/2];
for(int i=1;i<=m;i++)
ans+=abs(b[i]-mid);
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=t;i++)
{
int x,y;
scanf("%d%d",&x,&y);
row[x]++;
col[y]++;
}
if(t%n && t%m)
{
printf("impossible\n");
return 0;
}
if(t<n && t<m)
{
printf("impossible\n");
return 0;
}
if(t%n==0)
solve_row();
if(t%m==0)
solve_col();
if(t%m==0 && t%n==0) printf("both %lld\n",ans);
else if(t%n==0) printf("row %lld\n",ans);
else if(t%m==0) printf("column %lld\n",ans);
return 0;
}