ACwing 147 数据备份 贪心 set

LINK:数据备份

以前做过这种贪心 不过没有好好的证明 这次来严格的证明一下。

不难发现 最后的答案 选择的所有两对公司必然相邻。

所以排序后 把数组变成ai-ai-1. 这样问他的模型就是 n-1个数从中选出k个数 且任意两个数不能相邻 求和的最小值。

k==1时显然是全局最小值。

k==2的时候 有两种方法:全局最小值 和全局最小值不相邻的 最小数字。还有一种 把全局最小值扔了 选他们两边的数字。

此时 选出全局最小值之后把左右两边元素给去掉 因为这两个决策假了。

加入一个新决策 :两边元素之和-中间的元素。

然后可以发现 此时决策集合完全覆盖了我们上述的分析。

考虑拓展到k比较大的情况。

我们不断维护决策集合的完整性。而且对于每一个局面都是一样的。所以从递归来看这是正确的。

换个角度:从一个局面最优转到另一个局面 可以发现 此时如果我们选择了上次新决策那么符合我们前面的结论2.

如果选择了其他元素符合前面的结论1.

对于一个新局面来说其最优也是来自两个结论。

综上 做出的所有决策都是 结论1和结论2的一种 这对于所有的局面都是最优的选择 所以是正确的。

const int MAXN=100010;
int n,k;
ll ans;
int l[MAXN],r[MAXN];
ll w[MAXN];
ll a[MAXN];
multiset<pii>s;
multiset<pii>:: iterator it,itt,itt1;
int main()
{
    //freopen("1.in","r",stdin);
    get(n);get(k);
    rep(1,n,i)get(a[i]);
    sort(a+1,a+1+n);
    rep(1,n-1,i)w[i]=a[i+1]-a[i],s.insert(mk(w[i],i)),l[i]=i-1,r[i]=i+1;
    w[0]=inf;w[n]=inf;s.insert(mk(w[0],0));s.insert(mk(w[n],n));
    while(k--)
    {
        it=s.begin();
        ans+=(*it).F;
        int x=(*it).S;
        int L=l[x];
        int R=r[x];
        s.erase(it);
        itt=s.find(mk(w[L],L));
        s.erase(itt);
        itt1=s.find(mk(w[R],R));
        s.erase(itt1);
        w[x]=w[R]+w[L]-w[x];
		l[x]=l[L];r[x]=r[R];
		r[l[L]]=x;l[r[R]]=x;
        s.insert(mk(w[x],x));
    } 
    putl(ans);
    return 0;
}
posted @ 2020-04-17 15:59  chdy  阅读(137)  评论(0编辑  收藏  举报