三分 cf439D

题意:给你两个数列n,m,然后n里面的数可以每次+1,m里面的数可以每次-1,那么要使n里面的最小值大于m里面的最大值,

最少的操作数(每次+1or-1都是一次操作)

思路:

Let us define a function f. Function f(k) = cost needed to make array a elements  ≥  k + cost needed to make array b elements  ≤  k

Instead of proving it formally, try checking the property on many random test cases. You will realize that f is convex.(凹函数)

证明:设F(x)= E(x-ai)(if(x>ai))+E(bi-x)(if(bi>x))

那么对于这个函数求导,即F'(x)=t1-t2(t1与t2分别是上面小于大于x的元素的个数)

很明显,当x很小的时候,F'(x)<0,逐渐变为0,然后x很大的时候F'(x)>0,那么这个导数就是一个递增的,那么F(x)就是一个凹函数,既然是凹函数,那么就可以用三分求极值。

一种简便的做法,对n正着排序,对m倒着排序,然后对ai与bi做如下操作,如果bi>ai,那么ans+=bi-ai;

最后就是结果。

#include
#include
#include
#include
using namespace std;
#define LL long long
LL a[100005],b[100005];
int n,m;
LL ans,ans2;
LL cal(LL x)
{
    ans=0;
    for(int i=0; ix)
        {
            ans+=b[i]-x;
        }
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        ans2=1e20;
        for(int i=0;i>a[i];
        for(int i=0;i>b[i];
        LL ll=1,lr=(LL)1e9;
        LL mid,midmid,mv,mmv;
        while(ll<=lr){
            mid=ll+(lr-ll)/3;
            midmid=ll+2*(lr-ll)/3;
            mv=cal(mid);
            ans2=min(ans2,mv);
            mmv=cal(midmid);
            ans2=min(ans2,mmv);
           if(mv>=mmv){
                ll=mid+1;
            }
            else lr=midmid-1;
        }
        cout<

你可能感兴趣的:(三分 cf439D)