三分,你比二分多一分

三分应用于最优化问题的求解。在解题时没必要给出证明,只要知道问题不满足单调性,就可以尝试用三分搜索极值点,而且三分整数很少见,因为除非能够证明这种策略是正确的(即完全符合凸函数的性质,但是通常极值点不会在整点取得,如果三分整数,那么函数也不是连续的了),否则很可能会错误,而三分应用在小数中是最常见的,比如说三分角度,三分坐标等等。

这句话里面重点是什么呢?问题不满足单调性!极值点!

如:

 

 

但我觉得三分相比二分最精髓的是什么呢?

有了互相比较的值!

我们来想一下,二分通常是怎么写的,是不是 if (mid<答案)then  { left or right=mid  }

但是如果题目就叫你求这个答案呢?三分就很有用处了。

对于一组数据,如果它有极值点,我们就用三分。

具体怎么实现,就是我的当前左答案小于or大于右答案,然后 left or right=mid ,逐步逼近极值点。

我们来一道例题

https://nanti.jisuanke.com/t/43512

很明显这题是有极值点,且只有一个,不懂怎么证明的话可以像我一样,写一个暴力程序,一个一个枚举,看枚举出来的每个值要移动多少步才符合要求,然后你就发现数据是递减后递增的。

一开始我只知道二分,所以很显而易见的做不出来,贪心又不会贪,最终只能送人头。

这题三分的做法,就是三分第一个啤酒摊的坐标,然后左边右边进行比较,之后就是常规三分做法

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
int a[1000005],i,n,m;
ll l,r,mid1,mid2,ans1,ans2,ans;
using namespace std;
ll solve(ll x)
{
    ll ans=0;
    for (int i=1;i<=n;i++)
    {
        ans+=abs(a[i]-x);
        x+=m;
    }
    return ans;
}
int main()
{
    while (~scanf("%d%d",&n,&m))
    {
    for (i=1;i<=n;i++)    scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    l=-1e12;
    r=1e12;
    ans=INF;
    for (i=1;i<=100;i++)
    {
        mid1=l+(r-l)/3;
        mid2=r-(r-l)/3;
        ans1=solve(mid1);
        ans2=solve(mid2);
        if (ans1>ans2) l=mid1;
            else r=mid2;
        ans=min(ans,min(ans1,ans2));
    }
    cout<<ans<<endl;
    }
    return 0;
}
View Code
posted @ 2020-02-26 23:04  Y-KnightQin  阅读(198)  评论(0编辑  收藏  举报