传送门:
http://codeforces.com/contest/620/problem/D
很sb的一道题,暴力加二分即可以过!!
题意:
两个数列,最多可以交换两次,使得二数列和的差最小。
把求得值得表达式子计算出来就是
sum1-2*a[i]-sum2+2*b[i]
然后根据这个式子分项进行计算就可以了
直接暴力模拟一次,和两次的情况即可,两次的时候二分找到临界两个,比下大小就可以了
shit
第一次被样例给坑了,我的那种输出是多解中的一种,不过和样例不一样罢了
还wrong了一发,主要是由于二分的时候多加了个绝对值,因为值可能是负的,所以就错了!!!
一定要注意负值,不要随意加绝对值!!!
注意两点,一是这种需要排序和去重的一定用map, 二是map的二分查找返回值是it迭代器,一定不要弄错了,还有就是注意迭代器越界问题的判断!!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
map<ll,pair<int,int>>mm;
map<ll,pair<int,int>>::iterator it;
const int maxn=2e3+10;
ll a[maxn],b[maxn],n,m;
ll sum1,sum2;ll minn=1e18;
pair<int,int>ans1,ans2;int num;
void check(ll a,ll b,pair<int,int>c,pair<int,int>d){
if(abs(a-b)<minn){
minn=abs(a-b);num=2;
ans1=c;ans2=d;
}
}
int main(){
cin>>n;sum1=0;sum2=0;num=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);sum1+=a[i];
}cin>>m;
for(int i=1;i<=m;i++){
scanf("%lld",&b[i]);sum2+=b[i];
}
// if(sum1<sum2) swap(sum1,sum2);
minn=abs(sum1-sum2);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(abs(sum1-2ll*a[i]-sum2+2ll*b[j])<minn){
num=1;
minn=abs(sum1-a[i]*2ll-sum2+2ll*b[j]);ans1={i,j};
}
}
}
// if double needs
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
mm[2ll*(a[i]+a[j])]={i,j};
}
}
for(int i=1;i<=m;i++){
for(int j=i+1;j<=m;j++){
ll sum=sum1-sum2+2ll*(b[i]+b[j]);
it=mm.lower_bound(sum);
if(it!=mm.end()) check(sum,it->first,it->second,{i,j});
if(it!=mm.begin()) {it--;check(sum,it->first,it->second,{i,j});}
}
}
printf("%lld\n",minn);
if(num==1){
puts("1");printf("%d %d\n",ans1.first,ans1.second);
}
else if(num==2){
puts("2");printf("%d %d\n",ans1.first,ans2.first);
printf("%d %d\n",ans1.second,ans2.second);
}
else puts("0");
return 0;
}