ch0502 七夕祭

http://contest-hunter.org:83/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0502%20%E4%B8%83%E5%A4%95%E7%A5%AD

一  在解题之前,先了解一下中位数的用处。

先看一下这个题:http://contest-hunter.org:83/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0501%20%E8%B4%A7%E4%BB%93%E9%80%89%E5%9D%80

我们要在这一条数轴选一个地点,使其到其它所有的点的距离之和最小。那么这个点就是所有点的中位数。证明的话我们可以采用反证法:

假设我们选择X点,在X点的左边有p个点,右边有q个点。如果p>q,那么当我们把X往左边移动y个点时,距离之和就会变小q-p;反之如果q<p,那么往右边移动就会减小距离之和。故q==p时,距离之和最小。

二 回到本题来:

当我们交换左右的时候,我们改变某两列发的情况,对行并没有改变。同理交换上下的时候,对列也没有改变。故可以考虑,这两者并没有什么影响。

那现在让我们考虑交换左右的情况,共有m列。如果他感兴趣的摊位的个数不能整除m时,那显然这个时候我们是不能通过交换左右的位置来使每一列都想等的。如果感兴趣的摊位能够整除m时,我们又怎样求最少的交换次数呢。说到这里我们不得不提一下“均分纸牌”:

有m个人,每个人有c[i]张牌,每个人每次可以把自己手中的一张牌交给他相邻的人。问最少多少步操作可以使得每个人拥有的纸牌数相同。(我们认为最后一定是可以均分的)。那现在我们假设最后每个人都均分到k张牌。故第一个人所做的操作就是c[1]-k(这k张牌可能是他给第二个人的,也可能是第二个人给他的),第二个人所做的操作为 从c[1]+c[2]-k*2;第三个人为c[1]+c[2]+c[3]-k*3;故总的操作为\sum_{i=1}^{m}k*i-g[i]],g[i]是c[i]的前缀和。现在我们先把c[i]都减去k,令A[i]=c[i]-k,则答案可以写为\sum_{i=1}^{n}abs(s[i]),其中s[i]是A[i]的前缀和。

 

好了好了,再次回到本题,本体中,第一列和最后一列是可以交换的,故构成了一个环。但其实其中有两个人之间是没有交换操作的,比如我们从第i个人开始操作,那么对第i个人处理之后第i个人就是已经满足条件了,当我们循环到最后一个人时(i前面的一个人),那们这个人也肯定也满足条件了,如果他不满足条件的话,假设他需要进行w次操作才能满足条件,那就会导致第i个人不满条件了,故第i个人和他之前的人肯定是没有进行交换的。这样的话,我们就可以枚举这个断点了。如果在第k个人之后把这个环断开,那这m个人持有的纸牌数,前缀和分别是:

A[k+1]         s[k+1]-s[k]

A[k+2]           s[k+2]-s[k]

...............................................

A[m]            s[1]+s[m]-s[k]

...............................................

A[k]                s[k]+s[m]-s[k]

这里的A是减去均分k之后数。

所以答案就是\sum_{i=1}^{m}abs(s[i]-s[k])。那k取什么值时答案最小呢?仔细看一看上面这个式子,是不是和开始讲的中位数很像,没错,就是中位数。

好了,上代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const long long MAXN = 100000 + 10;
long long d[MAXN], c[MAXN],sum[MAXN];
long long n, m, k;

long long solve(long long a[MAXN], long long n) {
	long long k=a[0]/n;
	for (long long i = 1; i <=n; i++) {
		a[i] = a[i] - k;
		sum[i] = sum[i - 1] + a[i];
	}

	sort(sum+1,sum+1+n);
	long long ans=0;
	for (long long i = 1; i <= n; i++)ans += abs(sum[i]-sum[(n+1)/2]);
	return ans;
}

int main() {
	cin >> n >> m >> k;
	long long a, b;
	for (long long i = 1; i <= k; i++) {
		cin >> a >> b;
		d[a]++; c[b]++;
	}

	for (long long i = 1; i <= n; i++)d[0] += d[i];
	for (long long i = 1; i <= m; i++)c[0] += c[i];

	if (d[0] % n == 0 && c[0] % m == 0)
		printf("both %lld\n", solve(d, n) + solve(c, m));
	else if (d[0] % n == 0)
		printf("row %lld\n", solve(d, n));
	else if (c[0] % m == 0)
		printf("column %lld\n", solve(c, m));
	else
		printf("impossible\n");
	return 0;
}

 

 

 

 

猜你喜欢

转载自blog.csdn.net/xiaonanxinyi/article/details/84590766