问题描述
七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。于是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
2 3 4
1 3
2 1
2 2
2 3
样例输入2
3 3 3
1 3
2 2
2 3
样例输出
样例输出1
row 1
样例输出2
both 2
原题: 七夕祭
思路解析
经过分析我们可以发现,交换左右两个相邻的摊点 只会改变某两列 中c1感兴趣的摊点数,不会改变每行 中 c1感兴趣的摊点数。
交换上下两个相邻的摊点同理。
所以我们可以把本题分成两个互相独立的部分计算,即类比为行,列方向上的两次“环形均分纸牌”问题。而“环形均分纸牌”问题又可类比为从中位数处断环的“线性均分纸牌”问题。
线性均分纸牌解析: 看这里
环形均分纸牌解析: 看这里
即:
1、通过最少次数的左右交换使每列中c1感兴趣的摊点数相同。
2、通过最少次数的左右交换使每行中c1感兴趣的摊点数相同。
以第一种情况为例,我们的目标就是让每列中有T/M个 c1感兴趣的摊点,这样就将此问题化简成基本的环形均分纸牌问题了。
我们照常从中位数处断环,然后将它化简为基本的线性均分纸牌问题,再根据前缀和的思想,求出最小代价。
第二种情况同理。
而第三种情况根据上面的分析,就是第一种情况的最小代价加上第二种情况的最小代价。
代码
#include<iostream>
using namespace std;
#include<string>
#include<algorithm>
long X[100000];
long Y[100000];
long num_X[100000] = { 0 };
long num_Y[100000] = { 0 };
long S[100000];
long S2[100000];
void main()
{
// N,M,T
long N, M, T;
cin >> N >> M >> T;
// x行y列
long x, y;
for (long i = 0; i < T; i++)
{
cin >> x >> y;
X[i] = x;
num_X[x]++;
Y[i] = y;
num_Y[y]++;
}
string ret = "impossible";
if (T % M && T % N)
cout << ret;
// 只能使各行一样多
else if (!(T % N) && (T % M))
{
ret = "row";
S[N - 1] = 0;
long avg = T / N;
long ans = 0;
// 从中位数处断开
for (long i = N - 2; i >= 0; i--)
S[i] = S[i + 1] - (num_X[X[i]] - avg);
sort(S, S + N);
for (long i = 0; i < N; i++)
ans += abs(S[i] - S[(N / 2)]);
cout << ret << " " << ans;
}
// 只能使各列一样多
else if (!(T % M) && (T % N))
{
ret = "column";
S[M - 1] = 0;
long avg = T / M;
long ans = 0;
// 从中位数处断开
for (long i = M - 2; i >= 0; i--)
S[i] = S[i + 1] - (num_Y[Y[i]] - avg);
sort(S, S + M);
for (long i = 0; i < M; i++)
ans += abs(S[i] - S[(M / 2)]);
cout << ret << " " << ans;
}
// 行列均可满足要求
else
{
ret = "both";
S[N - 1] = 0;
long avg1 = T / N;
long ans = 0;
// 从中位数处断开
for (long i = N - 2; i >= 0; i--)
S[i] = S[i + 1] - (num_X[X[i]] - avg1);
sort(S, S + N);
for (long i = 0; i < N; i++)
ans += abs(S[i] - S[(N / 2)]);
S2[M - 1] = 0;
long avg2 = T / M;
// 从中位数处断开
for (long i = M - 2; i >= 0; i--)
S2[i] = S2[i + 1] - (num_Y[Y[i]] - avg2);
sort(S2, S2 + M);
for (long i = 0; i < M; i++)
ans += abs(S2[i] - S2[(M / 2)]);
cout << ret << " " << ans;
}
}