Codeforces-620d Professor GukiZ and Two Arrays

题目大意:

给你两个数组,一个长度为n,一个长度为m,第一个数组各个元素的和为suma,第二个数组各个元素的和为sumb,现在想要通过交换两个数组元素的方式使Abs(suma - sumb)最小,但是交换的次数不能超过两次。让你输出Abs(suma - sumb)的最小值,并输出这个值发生的时候的交换次数和交换元素在两个数组中的下标。


解题思路:

首先看到这题我们需要明确一下数据大小,n和m的大小都是只有2000,而交换的次数不会超过两次,那么我们就可以简单暴力的写了。

枚举交换的次数:

当不交换的时候,就是一次遍历数组然后得出结果的情况。复杂度O(n+m)

当交换一次的时候,枚举两个数组会交换的所有情况即可。复杂度O(nm)

当交换两次的时候:

首先,假设第一个数组交换的元素为下标a和b的元素,第二个数组交换的元素为下标c和d的元素。

然后,我们可以简单的得到一个算式Abs(suma' - sumb')=Abs(suma - sumb - 2 * (array1[a] + array1[a]) - 2 * (array2[c] + array2[d]))

我们的目的是计算最小的Abs(suma' - sumb'),而abs不可能为负数

所以,当我们已知suma - sumb - 2 * (array1[a] + array1[b])的情况下,可以找离-(suma - sumb - 2 * (array1[a] + array1[b]))最近的一个元素。

怎么找呢,前面说了,在已知suma - sumb - 2 * (array1[a] + array1[b])的情况下,也就是说我们已知array1[a]+array1[b],所以只需要先在两个数组中,枚举出所有的两个元素相加的情况,就能够利用二分查找,得到我们想要的结果了。

复杂度是O(n*(n-1) / 2 + m*(m-1) / 2 + n * (n - 1) / 2 * log(m * (m-1) / 2))。也就是O(n^2)的复杂度。


代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e3 + 2;

int a[maxn], b[maxn];
vector<pair<int, int> > vec;
vector<pair<long long, pair<int, int> > > aa, bb;

template<typename T> T Abs(T x) { return (x >= 0 ? x : -x); }
template<typename T> T Max(T x, T y) { return (x >= y ? x : y); }
template<typename T> T Min(T x, T y) { return (x <= y ? x : y); }

int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	int n, m; long long ans = 0;
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		ans += a[i];
	}
	cin >> m;
	for (int i = 0; i < m; ++i) {
		cin >> b[i];
		ans -= b[i];
	}
	long long sum = ans; ans = Abs(ans);
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			if (ans > Abs(sum - 2 * a[i] + 2 * b[j])) {
				ans = Abs(sum - 2 * a[i] + 2 * b[j]);
				vec.clear();
				vec.push_back(make_pair(i + 1, j + 1));
			}
		}
	}
	
	if (!(n <= 1 || m <= 1)) {
		aa.clear();
		for (int i = 0; i < n; ++i) 
			for (int j = i + 1; j < n; ++j) 
				aa.push_back(make_pair(a[i] + a[j], make_pair(i + 1, j + 1)));
		for (int i = 0; i < m; ++i) 
			for (int j = i + 1; j < m; ++j)
				bb.push_back(make_pair(b[i] + b[j], make_pair(i + 1, j + 1)));
		
		sort(aa.begin(), aa.end());
		sort(bb.begin(), bb.end());
		
		for (decltype(aa.size()) i = 0; i < aa.size(); ++i) {
			long long tmp = (2 * aa[i].first - sum) / 2;
			int idx = lower_bound(bb.begin(), bb.end(), make_pair(tmp, make_pair(0, 0))) - bb.begin();
			if (idx < bb.size() && ans > Abs(sum - 2 * aa[i].first + 2 * bb[idx].first)) {
				ans = Abs(sum - 2 * aa[i].first + 2 * bb[idx].first);
				vec.clear();
				vec.push_back(make_pair(aa[i].second.first, bb[idx].second.first));
				vec.push_back(make_pair(aa[i].second.second, bb[idx].second.second));
			}
			if (idx > 0 && ans > Abs(sum - 2 * aa[i].first + 2 * bb[idx - 1].first)) {
				ans = Abs(sum - 2 * aa[i].first + 2 * bb[idx - 1].first);
				vec.clear();
				vec.push_back(make_pair(aa[i].second.first, bb[idx - 1].second.first));
				vec.push_back(make_pair(aa[i].second.second, bb[idx - 1].second.second));
			}
		}
	}
	
	cout << ans << endl;
	cout << vec.size() << endl;
	for (auto& a: vec) 
		cout << a.first << " " << a.second << endl;
	return 0;
}


posted @ 2017-08-27 22:49  _Wilbert  阅读(160)  评论(0编辑  收藏  举报