bzoj1150 [CTSC2007]数据备份Backup

来源:互联网 发布:软件众包平台 编辑:程序博客网 时间:2024/06/01 10:44

题目

应该是道贪心题目。如何贪心呢?

还是很巧妙的啊。

每次选最小的一个数,再把它左右两边数之和减去这个数差回去,小根堆的应用。

不会证明为什么233。找规律?

#include<iostream>#include<algorithm>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<cmath>#define LL long long#define MAXN 100000using namespace std;struct point{    int val;    int id;};point A[MAXN+1];int n;int B[MAXN+1],x,y;int pre[MAXN+1],aft[MAXN+1];int k,cur,lst;bool E[MAXN+1];LL ans;void down(int r,int n){    point v;    v=A[r];    int k;    k=r*2;    while(k<=n)    {        if(A[k].val>A[k+1].val&&k<n)k++;        if(A[r].val<A[k].val)break;        A[r]=A[k];        r=k;        k=k*2;        A[r]=v;    }}void build(int n){    for(int i=n/2;i>=1;i--)        down(i,n);}int main(){    scanf("%d%d",&n,&k);    for(int i=1;i<=n;i++)    {        scanf("%d",&cur);        A[i].id=i;        pre[i]=i-1;        aft[i]=i+1;        B[i]=A[i].val=cur-lst;        lst=cur;    }    B[1]=A[1].val=1e9;    B[n+1]=A[n+1].val=1e9;    pre[n+1]=n;    n++;    build(n);    ans=0;    memset(E,true,sizeof(E));    for(int i=1;i<=k;i++)    {        while(!E[A[1].id])        {            A[1]=A[n];            n--;            down(1,n);        }        ans+=A[1].val;              B[A[1].id]=A[1].val=min((int)1e9,B[pre[A[1].id]]+B[aft[A[1].id]]-A[1].val);        E[pre[A[1].id]]=E[aft[A[1].id]]=false;        int Pr=pre[pre[A[1].id]];        pre[A[1].id]=Pr;        aft[Pr]=A[1].id;        int Af=aft[aft[A[1].id]];        aft[A[1].id]=Af;        pre[Af]=A[1].id;        down(1,n);    }    printf("%lld",ans);    return 0;}

删除的话,打一个标记,如果堆顶是的话,就删除。

原创粉丝点击