问题 N: 七夕祭
问题 N: 七夕祭
问题 N: 七夕祭
时间限制: 1 Sec 内存限制: 128 MB
题目描述
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。于是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.交换同行的摊点不影响每一行的摊点数
2.交换同列的摊点不影响每一列的摊点数
观察数据范围,1≤N,M≤100000,如果用二维数组来存显然MLE,又因为我们得到上述两个性质,我们可以用两个数组来分别存储行和列的兴趣点
这样就变成两次"能否均分纸牌"的问题了,不同于洛谷的均分纸牌,这里每次只能移动一张
那么首先分别求出行的平均数(T/N)和列的平均数(T/M),如果无法整除那么肯定不能均分
如果整除的话:
我们的目标是将每一行(列)的摊点数都变成平均数(ave),从第一个开始,如果多余ave,那么把其中的摊点向后交换,后面那一行(列)的数量增加这个Δ,反之减少Δ,以此类推直到最后一个肯定就不用移动了,那么交换次数总和就等于每次的Δ的和,由于前一个的Δ会影响下一个的Δ,所以我们应该需要的是Δ前缀和绝对值的和,这个Δ为了方便使用,我们可以在一开始便把每个行(列)都减去平均值
对于这个题,由于万能的空间扭曲,使这条线变成了一个环,那么每一个摊点都可以作为起始点进行操作,怎么求最小值呢?
因为我们每一行(列)都已经减去了平均值,那么每一行(列)兴趣点-ave的总和为0,我们假设有n个数,前缀和为s[i],即s[n]=0;
如图
如果从第2行(列)开始计算,
ans=|s[2]-s[1]|+|s[3]-s[1]|+.....+|s[n]-s[1]|+|s[1]+s[n]-s[1]|
=Σ|s[i]-s[1]|(i从2到n)+|s[n]|;
=Σ|s[i]-s[1]|(i从2到n)+0
=Σ|s[i]-s[1]|(i从1到n)
如果从第3行(列)开始计算,
ans=|s[3]-s[2]|+|s[4]-s[2]|+.....+|s[n]-s[2]|+|s[1]+s[n]-s[2]|+|s[2]+s[n]-s[2]|
=Σ|s[i]-s[2]|(i从3到n)+|s[1]+s[n]-s[2]|+|s[2]+s[n]-s[2]|
=Σ|s[i]-s[2]|(i从3到n)+|s[1]-s[2]|+0
=Σ|s[i]-s[2]|(i从1到n)
我们不难发现,从第k行(列)开始,无论k是几,最后的结果都是=Σ|s[i]-s[k]|(i从1到n)
那么我们仅需要找到这个s[k]即可
我们可以想到之前做过的"货仓选址"
那个题目是每个数都在数轴上,而且单调,那么我们可以将前缀和排下序就可以套用货仓选址的思想
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,t;
const int M=1e5+1;
long long l[M],r[M],a[M],b[M];//列 行
long long ans;
bool lb,rb;
int main()
{
cin>>n>>m>>t;
int ave_l=t/n,ave_r=t/m;
for(int i=1;i<=n;i++)
l[i]-=ave_l;
for(int i=1;i<=m;i++)
r[i]-=ave_r;
for(int i=1;i<=t;i++)
{
int x,y;
cin>>x>>y;
l[x]++;
r[y]++;
}
lb=!(t%n);
rb=!(t%m);
if(t%n&&t%m)
{
cout<<"impossible";
return 0;
}
if(lb)
{
for(int i=1;i<=n;i++)
a[i]=a[i-1]+l[i];
sort(a+1,a+1+n);
int sum=0;
for(int i=1,j=n;i<=j;j--,i++)
ans+=abs(a[j]-a[i]);
}
if(rb)
{
for(int i=1;i<=m;i++)
b[i]=b[i-1]+r[i];
sort(b+1,b+1+m);
for(int i=1,j=m;i<=j;j--,i++)
ans+=abs(b[j]-b[i]);
}
if(lb&&rb)
cout<<"both "<<ans;
else
if(lb)
cout<<"row "<<ans;
else cout<<"column "<<ans;
return 0;
}
-------------------------------------------
个性签名:曾经的我们空有一颗望海的心,却从没为前往大海做过真正的努力
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!