JZOJ4726. 种花

题目大意

给定一个 n 个点的环,每个点都有一个权值ai,现在要从中选出 m 个点。已经选择的点相邻的两个点不能选。
求最大权值和。

Data Constraint
n,m200000

题解

题解好机智!支持撤销的贪心!
ai 为关键字建立一个大根堆,每个位置维护一个双向链表。
假如当前我们取出了位置 k 上的数,删除k的前驱和后继,令 ak=apre+anextak ,再把 ak 放入堆中。
可以这样理解,删去了 k 的前驱和后继保证了不会取到相邻的数。ak=apre+anextak使得我们有机会撤销之前的操作。

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std ;

#define N 200000 + 10
struct Note {
    int v , h ;
    Note ( int V = 0 , int H = 0 ) { v = V , h = H ; }
} ;

bool operator < ( Note a , Note b ) { return a.v < b.v ; }

priority_queue < Note > Q ;

bool flag[N] ;
int a[N] , Pre[N] , Next[N] ;
int n , m , ans ;

int main() {
    scanf( "%d%d" , &n , &m ) ;
    for (int i = 1 ; i <= n ; i ++ ) {
        scanf( "%d" , &a[i] ) ;
        Pre[i] = (i + n) % (n + 1);
        Next[i] = (i + 1) % (n + 1) ;
        if ( Pre[i] == 0 ) Pre[i] = n ;
        if ( Next[i] == 0 ) Next[i] = 1 ;
        Q.push( Note( a[i] , i ) ) ;
    }
    if ( m > n / 2 ) { printf( "Error!\n" ) ; return 0 ;}
    while ( !Q.empty() && m ) {
        Note top = Q.top() ;
        Q.pop() ;
        if ( flag[top.h] ) continue ;
        m -- ;
        ans += top.v ;
        top.v = a[top.h] = a[Pre[top.h]] + a[Next[top.h]] - a[top.h] ;
        flag[Pre[top.h]] = flag[Next[top.h]] = 1 ;
        Pre[top.h] = Pre[Pre[top.h]] ;
        Next[top.h] = Next[Next[top.h]] ;
        Next[Pre[top.h]] = top.h ;
        Pre[Next[top.h]] = top.h ;
        Q.push( top ) ;
    }
    printf( "%d\n" , ans ) ;
    return 0 ;
}

以上.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值