前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【CodeForces 620D】Professor GukiZ and Two Arrays

【CodeForces 620D】Professor GukiZ and Two Arrays

作者头像
饶文津
发布2020-05-31 23:36:45
4120
发布2020-05-31 23:36:45
举报
文章被收录于专栏:饶文津的专栏饶文津的专栏

题意

两个数列,一个有n个数,另一个有m个数,让你最多交换两次两个数列的数,使得两个数列和的差的绝对值最小,求这个差的绝对值、最少交换次数、交换数对

分析

交换0次、1次可得到的最小的差可以枚举出来。

交换两次,如果枚举就超时了。

我们预处理把第一个数列两两组合的所有情况存储起来为u数组,并且按照大小排序,接着在另一个数列里枚举两个数后,用二分的方法,求交换后使得 差的绝对值最小 的u。

二分查找最接近的值可以用lower_bound函数。

代码

代码语言:javascript
复制
#include<stdio.h>
#include<cmath>
#include<map>
#include<utility>
#define N 2005
#define ll long long

using namespace std;
ll a[N],b[N],n,m,suma,sumb,v,ans,c;

map<ll,pair<int,int> >u;
map<ll,pair<int,int> >::iterator it;
pair<int,int>swap1,swap2;

void update(int i,int j)
{
    if(abs(c-it->first) < v)
    {
        ans=2;
        v = abs(c - it->first);
        swap1 = it->second;
        swap2 = {i,j};
    }
}

int main()
{
    scanf("%lld",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&a[i]);
        suma+=a[i];
    }

    scanf("%lld",&m);
    for(int i=1; i<=m; i++)
    {
        scanf("%lld",&b[i]);
        sumb+=b[i];
    }

    v=abs(suma-sumb);
    if(!v)
    {
        printf("0\n0\n");
        return 0;
    }

    for(int i=1; i<n; i++)
        for(int j=i+1; j<=n; j++)
            u[(a[i]+a[j])*2LL] = {i,j};

    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
            if(abs(suma-sumb-2LL*(a[i]-b[j]))<v)
            {
                ans=1;
                v=abs(suma-sumb-2LL*(a[i]-b[j]));
                swap1= {i,j};
            }
    for(int i=1; i<m; i++)
        for(int j=i+1; j<=m; j++)
        {
            c=suma-sumb+2LL*(b[i]+b[j]);
            it=u.lower_bound(c);
            if( it != u.end() )
                update(i,j);
            if( it != u.begin() )
            {
                it--;
                update(i,j);
            }
        }

    printf("%lld\n%lld\n",v,ans);

    if(ans==1)printf("%d %d\n",swap1.first,swap1.second);
    if(ans==2)printf("%d %d\n%d %d\n",swap1.first,swap2.first,swap1.second,swap2.second);

    return 0;
}

2017.7.21 ps. 今天再做这题,wa了八下。因为自己写的二分,一开始忘记考虑n==1的情况(这样就不存在a数组里选两个加起来了,二分的结果没有意义)。之后发现我二分查找的是加了绝对值的,显然不需要加绝对值。以及如果二分查找的值不存在,那么得到的就是大于它的第一个值,所以还要考虑小于它的第一个值。最终AC的代码如下:

代码语言:javascript
复制
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
#define N 2001
int n,m,a[N],b[N];
struct Node{
    ll a,b,v;
}sum[N*N];
ll sa,sb;
int x[2],y[2];
int cnt;
ll ans;
bool cmp(const Node& a,const Node& b){
    return a.v<b.v;
}
int bs(ll s){
    int l=1,r=cnt;
    while(l<r){
        int mid=l+r>>1;
        if(sum[mid].v<s)
            l=mid+1;
        else
            r=mid;    
    }
    return l;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",a+i),sa+=a[i];
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
        scanf("%d",b+i),sb+=b[i];

    for(int i=1;i<n;++i)
        for(int j=i+1;j<=n;++j)
            sum[++cnt]=(Node){i,j,2LL*(a[i]+a[j])};
    
    ans=abs(sb-sa);

    sort(sum+1,sum+1+cnt,cmp);
    int k=0;

    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            ll t=abs(sa-a[i]*2-sb+b[j]*2);
            if(t<ans){
                ans=t;
                k=1;
                x[0]=i;y[0]=j;
            }
        }
    if(cnt){
        for(int i=1;i<m;++i)
            for(int j=i+1;j<=m;++j){
                ll t=sa-sb+2LL*(b[i]+b[j]);
                int d=bs(t);
                for(int g=-1;g<1;++g)if(d+g>0&&d+g<=cnt){
                    ll tans=abs(t-sum[d+g].v);
                    if(tans<ans){
                        ans=tans;
                        k=2;
                        x[0]=sum[d+g].a;y[0]=i;
                        x[1]=sum[d+g].b;y[1]=j;
                    }
                }    
            }
    }
    printf("%lld\n%d\n", ans,k);
    for(int i=0;i<k;++i)
        printf("%d %d\n",x[i],y[i]);
    return 0;
}
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-02-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题意
  • 分析
  • 代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com