一个环形广场周围有 n 个空位,第 i 个空位有一个美观度 ai
现在想把 m 颗树种进这些空位中,每个种了树的位置都会为广场提供其相 应的美观度
由于某些规划问题,相邻两个空位中不能同时种上树,试求可能取得的最大 美观度
【输入格式】
第一行包含两个正整数 n 和 m
第二行包含 n 个正整数 a1~an
【输出格式】
一行一个整数,表示可能取得的最大美观度
【输入样例】
7 3 1 2 3 4 5 6 7
【输出样例】
15
【数据范围】
1≤2m+1≤n≤1.5×105
1≤ai≤103
如果直接按照美观度贪心的话肯定是不正确的
考虑相邻的三个元素a,b,c,如果b>a,b>c,a+c>b
明显应该选择a+c而不是b
为了解决这种情况,我们引入了一个叫替罪羊的概念,使得不改变贪心算法的大方向,而能够自动弥补错误
每次种树选取美观度最大的b,删掉自身及位置相邻的a,b,c,然后push一个新元素(替罪羊)a+c-b
如果b和替罪羊都被删掉则说明选择了a+c
如果只有b被删掉了则说明选择了b
1 #include <cstdio> 2 int n,m,ans=0,sz=0,heap[200001],nxt[200001],bak[200001],a[200001]; 3 void keep(int x) 4 { 5 int l=x*2,r=l+1,w,t; 6 if (l<=sz&&a[heap[l]]>a[heap[x]]) w=l;else w=x; 7 if (r<=sz&&a[heap[r]]>a[heap[w]]) w=r; 8 if (w!=x) 9 { 10 t=heap[x];heap[x]=heap[w];heap[w]=t; 11 keep(w); 12 } 13 } 14 void push(int x) 15 { 16 heap[++sz]=x; 17 for (int i=sz/2;i>=1;i/=2) keep(i); 18 } 19 void pop() 20 { 21 heap[1]=heap[sz--]; 22 keep(1); 23 } 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 if (n<m*2) 28 { 29 printf("Error!"); 30 return 0; 31 } 32 nxt[1]=2;nxt[n]=1;bak[1]=n;bak[n]=n-1; 33 for (int i=2;i<n;i++) nxt[i]=i+1,bak[i]=i-1; 34 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 35 for (int i=1;i<=n;i++) push(i); 36 for (int i=1;i<=m;i++) 37 { 38 int m,l,r; 39 m=heap[1],l=nxt[m],r=bak[m]; 40 while(bak[nxt[m]]!=m) 41 { 42 pop(); 43 m=heap[1],l=nxt[m],r=bak[m]; 44 } 45 bak[nxt[l]]=m;nxt[m]=nxt[l]; 46 nxt[bak[r]]=m;bak[m]=bak[r]; 47 ans+=a[m]; 48 a[m]=a[l]+a[r]-a[m];//替罪羊a+c-b 49 keep(1); 50 } 51 printf("%d",ans); 52 }