题目
题目链接:http://codeforces.com/contest/620/problem/D
题目来源:Educational Codeforces Round 6
简要题意:对于两个数组,在两数组间最多交换两次,求两数组之和的差的绝对值最小值。
题解
这题也属于理解起来简单,但是做起来比较棘手的题目,好题。
先分类,不交换的话可线性求出,交换 1 次可以平方枚举。
比较棘手的就是
2 次的情况了。首先我想到的一个办法是将所有的差塞入一个map然后利用原始数组和的差及枚举的一个差来二分。
但是这样做的问题是由于是要按照顺序来的,假如使用了相同的位置位置上的数已经发生了变化就会弄出来错误的答案了。
进一步考虑,假如换了相同的位置实际上就等价于换了一次,那先做 1 再做
2 不就能够不会更小就不会更新了么?然后就会继续坑了,因为这是假设两个差是正确的情况下,实际上map的两个差已经是错误的值了,错误的值可能更小,就会出问题了。实际上既然必然选择是两个不同的,可以枚举 a 中两数的组合塞进map然后枚举
b 中的两数来二分map。这样就可以避免两次选到同一位置的问题了,比赛时思维定势没能做出。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int N = 2005;
int a[N];
int b[N];
struct Result {
int cnt;
PII pr[2];
LL ans;
void printAns() {
printf("%I64d\n%d\n", ans, cnt);
for (int i = 0; i < cnt; i++) {
printf("%d %d\n", pr[i].fi, pr[i].se);
}
}
};
map<LL, PII> ma;
int main()
{
int n, m;
LL suma = 0, sumb = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", a+i);
suma += a[i];
}
scanf("%d", &m);
for (int i = 0; i < m; i++) {
scanf("%d", b+i);
sumb += b[i];
}
Result temp, ans;
ans.cnt = 0;
ans.ans = abs(suma-sumb);
LL tempsa, tempsb, tempans;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
tempsa = suma - a[i] + b[j];
tempsb = sumb - b[j] + a[i];
tempans = abs(tempsa-tempsb);
if (abs(tempsa-tempsb) < ans.ans) {
ans.ans = abs(tempsa-tempsb);
ans.cnt = 1;
ans.pr[0] = mp(i+1, j+1);
}
}
}
for (int i = 0; i < n; i++) {
for (int j = i+1; j < n; j++) {
ma[2LL * (a[i]+a[j])] = mp(i+1, j+1);
}
}
for (int i = 0; i < m; i++) {
for (int j = i+1; j < m; j++) {
LL x = suma-sumb+2LL*(b[i]+b[j]);
map<LL, PII>::iterator it = ma.upper_bound(x);
if(it != ma.end() && -x + it->fi < ans.ans) {
ans.ans = -x + it->fi;
ans.cnt = 2;
ans.pr[0] = mp(it->se.fi, i+1);
ans.pr[1] = mp(it->se.se, j+1);
}
if(it != ma.begin()) {
it--;
if(x - it->fi < ans.ans) {
ans.ans = x - it->fi;
ans.cnt = 2;
ans.pr[0] = mp(it->se.fi, i+1);
ans.pr[1] = mp(it->se.se, j+1);
}
}
}
}
ans.printAns();
return 0;
}