JZOJ4726. 种花

来源:互联网 发布:windows一键web安装包 编辑:程序博客网 时间:2024/04/30 04:38

题目大意

给定一个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 + 10struct 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
原创粉丝点击