牛客网,Wannafly挑战赛16 B题 AB序列 (三分板子)

链接:https://www.nowcoder.com/acm/contest/113/B

来源:牛客网

AB序列

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 262144K,其他语言524288K

64bit IO Format: %lld

题目描述

给长度为n的序列A,长度为m的序列B。可以给A序列里每个元素加上x且B序列里每个元素减去x (x可以是负数),问的最小值

输入描述:

第一行两个整数分别表示n,m

接下来一行n个整数表示序列A

接下来一行m个整数表示序列B

输出描述:

输出一个整数表示答案

示例1

输入

4 5

-8 2 -4 10

5 -5 -4 -9 10

输出

57

备注:

1<=n,m<=105

序列中的数为绝对值不超过10^9的整数 


思路:f(x)代表,f(x)是一个开口向上的抛物线。三分求最小值


代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=1e9+7;
const int M=2e4;
using namespace std;
const int N =1e5+100;
LL a[N],b[N],n,m;
LL abss(LL x)
{
    return x>0?x:-x;
}
LL solve(LL x)
{
    LL ans=0;
    for(int i=0;i<n;i++)
        ans+=abss(a[i]+x);
    for(int i=0;i<m;i++)
        ans+=abss(b[i]-x);
    return ans+abss(x);
}
LL Fl(LL x,LL y)
{
    if(x+y<0)
        return (x+y-1)/2;
    return (x+y)/2;
}
LL Fr(LL x,LL y)
{
    if(x+y<0)
        return (x+y)/2;
    return (x+y+1)/2;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(LL i=0;i<n;i++)
        scanf("%lld",&a[i]);
    for(LL i=0;i<m;i++)
        scanf("%lld",&b[i]);
    //因为l和r牵扯到了负数,那么就不能是简单的(l+r)/2了
    //因为/2的结果是向0偏移的,例如:l=-4,r=-1,(l+r)/2=-2,
    //例如:l=1,r=4,(l+r)/2=2,都是向零靠近的
    //但是我们想让midl向l偏移,midr向r偏移,所以分(l+r)>0和<0 两种情况
    //这个三分相当于板子,应该是所有的三分都可以使用,只需要更改solve()函数
    //以上废话都是为了防止三分死循环
    LL l=-1e9,r=1e9,midl,midr,ans;
    while(l<r)
    {
        midl=Fl(l,r);
        midr=Fr(midl,r);
        //求最小值用<=,求最大值用>=
        if(solve(midl)<=solve(midr))
        {
            r = midr-1;
            ans=midl;
        }
        else
        {
            l=midl+1;
            ans=midr;
        }
    }
    printf("%lld\n",solve(ans));
}
/*
附上一组数据
5 10
-10 -8 -10 -9 -6
5 6 8 -9 -10 -8 -7 -6 5 8

x=5 ans=95
*/


猜你喜欢

转载自blog.csdn.net/xiangaccepted/article/details/80456886