题意:
给定N≤2×103的两个序列,给定0≤k≤2次交换2个序列中一个数的操作,使得|suma−sumb|最小
分析:
k很小,所以可以枚举,k=0或者k=1直接搞就可以了
对于k=2,我们可以预处理出2个序列的C2n个数
对于交换的2个数ai,bj,a序列suma′=suma−ai+bj,b序列sumb′=sumb+ai−bj
dif′=suma′−sumb′=suma−sumb+2∗(−ai+bj)
假设原来的差是dif=suma−sumb,那么新的差就是dif′=dif+2∗(−ai+bj)
知道了ai,那么我们可以得到bj=−(dif−2∗ai)/2,这里直接除就可以,因为我们得不到那个.5的数
对于bj我们排序新的序列,就可以直接二分了
dif′带绝对值,计算一个比它大和一个比它小的,就是2个差值最近的
代码:
//
// Created by TaoSama on 2016-01-22
// Copyright (c) 2015 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
typedef long long LL;
int n, m;
int a[N], b[N], ans[5];
void update(LL& cur, LL& minv, int a1, int a2, int a3, int a4) {
if(cur < minv) {
minv = cur;
ans[1] = a1;
ans[2] = a2;
ans[3] = a3;
ans[4] = a4;
}
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
// ios_base::sync_with_stdio(0);
while(scanf("%d", &n) == 1) {
LL suma = 0, sumb = 0;
for(int i = 1; i <= n; ++i) scanf("%d", a + i), suma += a[i];
scanf("%d", &m);
for(int i = 1; i <= m; ++i) scanf("%d", b + i), sumb += b[i];
LL dif = suma - sumb, minv = abs(dif);
for(int i = 1; i <= 4; ++i) ans[i] = -1;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
LL cur = abs(dif + 2LL * (-a[i] + b[j]));
update(cur, minv, i, j, -1, -1);
}
}
vector<pair<LL, pair<int, int> > > va, vb;
for(int i = 1; i <= n; ++i)
for(int j = i + 1; j <= n; ++j)
va.push_back({a[i] + a[j], {i, j}});
for(int i = 1; i <= m; ++i)
for(int j = i + 1; j <= m; ++j)
vb.push_back({b[i] + b[j], {i, j}});
sort(vb.begin(), vb.end());
for(auto &x : va) {
LL cur = dif - 2 * x.first;
auto iter = lower_bound(vb.begin(), vb.end(),
make_pair(-cur / 2, make_pair(-1, -1)));
if(iter != vb.end()) {
LL tmp = abs(cur + 2 * iter->first);
update(tmp, minv, x.second.first, x.second.second, iter->second.first,
iter->second.second);
}
if(iter != vb.begin()) {
--iter;
LL tmp = abs(cur + 2 * iter->first);
update(tmp, minv, x.second.first, x.second.second, iter->second.first,
iter->second.second);
}
}
if(ans[1] == -1) printf("%I64d\n0\n", minv);
else if(ans[3] == -1) {
printf("%I64d\n1\n", minv);
printf("%d %d\n", ans[1], ans[2]);
} else {
printf("%I64d\n2\n", minv);
printf("%d %d\n", ans[1], ans[3]);
printf("%d %d\n", ans[2], ans[4]);
}
}
return 0;
}
这个题对于k=2的情况,使2个序列都有序,还可以使用two pointers来更新,复杂度减少了一个log
由于差值最小是0,对于2个序列的two pointers的过程,因为bj不断增大,整个dif′也不断增大
显然我们不要的部分是<0的部分,根据这个就可以做了
代码:
//
// Created by TaoSama on 2016-01-22
// Copyright (c) 2015 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
typedef long long LL;
int n, m;
int a[N], b[N];
typedef pair<int, int> P;
P ans[3];
void update(LL& cur, LL& minv, P a1, P a2) {
if(cur < minv) {
minv = cur;
ans[1] = a1;
ans[2] = a2;
}
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
// ios_base::sync_with_stdio(0);
while(scanf("%d", &n) == 1) {
LL suma = 0, sumb = 0;
for(int i = 1; i <= n; ++i) scanf("%d", a + i), suma += a[i];
scanf("%d", &m);
for(int i = 1; i <= m; ++i) scanf("%d", b + i), sumb += b[i];
LL dif = suma - sumb, minv = abs(dif);
for(int i = 1; i <= 2; ++i) ans[i] = { -1, -1};
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
LL cur = abs(dif + 2LL * (-a[i] + b[j]));
update(cur, minv, {i, j}, { -1, -1});
}
}
vector<pair<LL, pair<int, int> > > va, vb;
for(int i = 1; i <= n; ++i)
for(int j = i + 1; j <= n; ++j)
va.push_back({a[i] + a[j], {i, j}});
for(int i = 1; i <= m; ++i)
for(int j = i + 1; j <= m; ++j)
vb.push_back({b[i] + b[j], {i, j}});
sort(va.begin(), va.end());
sort(vb.begin(), vb.end());
int j = 0;
for(int i = 0; i < va.size(); ++i) {
while(j < vb.size() && dif + 2 * (-va[i].first + vb[j].first) < 0) ++j;
if(j < vb.size()) {
LL cur = abs(dif + 2 * (-va[i].first + vb[j].first));
update(cur, minv, va[i].second, vb[j].second);
}
if(j - 1 >= 0) {
LL cur = abs(dif + 2 * (-va[i].first + 0LL + vb[j - 1].first));
update(cur, minv, va[i].second, vb[j - 1].second);
}
}
if(ans[1].first == -1) printf("%I64d\n0\n", minv);
else if(ans[2].first == -1) {
printf("%I64d\n1\n", minv);
printf("%d %d\n", ans[1].first, ans[1].second);
} else {
printf("%I64d\n2\n", minv);
printf("%d %d\n", ans[1].first, ans[2].first);
printf("%d %d\n", ans[1].second, ans[2].second);
}
}
return 0;
}