应该是道贪心题目。如何贪心呢?
还是很巧妙的啊。
每次选最小的一个数,再把它左右两边数之和减去这个数差回去,小根堆的应用。
不会证明为什么233。找规律?
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#define LL long long
#define MAXN 100000
using 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;
}
删除的话,打一个标记,如果堆顶是的话,就删除。