zoukankan      html  css  js  c++  java
  • 题解——种树(堆)

    题解——种树(堆)

    考试题目叫 so , 和这道种树几乎差不多


    题面

    Description

    cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

    Input

    第一行,两个正整数n,k。

    第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。

    Output

    输出1个数,表示cyrcyr种树的最大获利。

    in.1
    6 3
    100 1 -1 100 1 -1

    out.1
    200

    数据范围与约定

    对于20%的数据,n<=20。

    对于50%的数据,n<=6000。

    对于100%的数据,n<=500000,k<=n/2,在一个地方种树获利的绝对值在1000000以内。

    部分分做法

    20分做法:

    想怎样暴力,就怎样暴力。20分暴力做法之多。

    50分做法:

    DP,转移并不是特别难。
    我们定义 dp[ i ][ j ][ 1/0 ] 表示递推到第 i 位,已经选了 j 个数, 1/0 表示当前位是否选择
    实际上和没有上司的舞会的dp转移很像,不过是序列上的

    dp[ i ][ j ][ 1 ] = dp[ i-1 ][ j-1 ][ 0 ]
    dp[ i ][ j ][ 0 ] = max( dp[ i-1 ][ j ][ 0 ] , dp[ i-1 ][ j ][ 1 ] )
    

    答案取 max{ dp[ N ][ K ][ 1/0 ] } , 滚掉第一位以节省空间

    100% 数据思路

    主要思路

    1.处理选择矛盾的情况,即可以反悔。

    我们考虑,当选择了一个当前最大值 a[ i ] 后,发现其实最优值要选择a[ i-1 ] 和 a[ i+1 ], 为了可以反悔,在选择下一个时,我们把 a[ i ]修改为 a[ i-1 ] + a[ i+1 ] - a[i] 。所以当 a[i] 被选后反悔时,我们在之后的选择中,我们就可以删去先前 a[ i ]的贡献而选择旁边两个。如果不反悔则不选,这样可以满足整个结构的最优性。

    2.维护序列,不断满足上述条件

    最大值我们考虑使用大根堆(优先队列来维护),先把所有值和编号压入堆,并且记录左右值的编号,在选择了 a[ i ]后进行上述操作,同时更行左右值得编号即可。整个操作进行K次,由于存在负值,所以要不断取最大值。

    细节:
    边界是不能合并越界,处理下即可。

    #include<bits/stdc++.h>
    using namespace std ;
    #define ll long long
    const int MAXN = 500005  ;
    inline int read(){
    	int s=0,w=1 ; char g=getchar() ; while(g>'9'||g<'0'){ if( g=='-')w=-1;g=getchar() ;} 
    	while(g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s*w ;
    }
    priority_queue< pair<ll,int> >q ;
    int N , K , tot ; 
    ll ans = 0 , last = 0 ;
    struct ap{
    	int  l , r ; 
    	ll val ;
    	bool f ; 
    }t[ MAXN ];
    int main(){
    	t[ 0 ].val = -10000000000000005LL ; //边界
    	N = read() , K = read() ; tot = N ;
    	for( int i = 1 ; i <= N ; ++i ){
    		t[ i ].val = (ll)read() , t[ i ].l = i-1 , t[ i ].r = i+1 ;
    		q.push( make_pair(t[ i ].val , i) ) ;
    	}
    	t[ N ].r = 0 ;//边界
    	while( K-- ){
    		int u = q.top().second ;
    		if( t[ u ].f ){ K++;q.pop();continue; }
    		ll v = q.top().first ; q.pop() ;
    		ans += v ; t[ t[ u ].l ].f = t[ t[ u ].r ].f = true ;//更新答案
    		t[ u ].val = t[ t[ u ].l ].val + t[ t[ u ].r ].val - t[ u ].val ; 
    		t[ t[ t[ u ].l ].l ].r = u , t[ t[ t[ u ].r ].r ].l = u ;//updata,更新左右编号
    		t[ u ].l = t[ t[ u ].l ].l , t[ u ].r = t[ t[ u ].r ].r ;
    		q.push( make_pair( t[ u ].val , u ) ) ;
    		last = max( last , ans ) ;
    	}
    	cout<<last ;
    }
    

    如有不足,请大佬指出

  • 相关阅读:
    IIS部署网站 HTTP 错误 500.21
    Oracle常用操作表空间sql脚本
    oracle 11g错误ora-01033:oracle initialization or shutdown in progress解决办法
    关于OPC连接读写下位机PLC(转)
    oracle 日期格式操作
    第三方app抽奖发送微信红包实现
    XML 字符串解析
    VS2013 统计代码量(使用正则表达式)
    使用IntelliJ IDEA 配置Maven(入门)(转)
    学习方法分享 | 从JVM说起,聊聊Java的学习和复习!
  • 原文地址:https://www.cnblogs.com/ssw02/p/11528466.html
Copyright © 2011-2022 走看看