Codeforces D. Professor GukiZ and Two Arrays

12 篇文章 0 订阅
9 篇文章 0 订阅

传送门:
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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值