zoukankan      html  css  js  c++  java
  • 修剪草坪/选择数字(单调队列优化DP)

    双倍经验!!! 双倍快乐!!!

    题意:给定n个非负整数(a[1]...a[n]).现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大.

    分析:正难则反,设(f[i])表示表示不选第i头牛的最小代价,结果会发现:(f[i]=min(f[j])+a[i]),于是可以单调队列,(O(n))优美地过了本题.

    
    ll n,k,sum,cnt=1e16;
    ll val[100005];
    ll q1[100005],q2[100005],f[100005];
    int main(){
        n=read();k=read();
        for(ll i=1;i<=n;i++){
    		val[i]=read();
    		sum+=val[i];//记录下所有数的和
        }
        int head=0,tail=0;//设置队列头,尾指针
        for(int i=1;i<=n;i++){
    		f[i]=q1[head]+val[i];
    //当前的第i个数不选,表示出最小代价f[i]
    //q1[]是从小到大的单调队列,记录的是不选的代价
    		while(head<=tail&&q1[tail]>f[i])
            	tail--;
    //要把当前不选的代价塞进单调队列q1中
    		while(head<=tail&&q2[head]<i-k)
            	head++;
    //q2[]也是从小到大的单调队列,记录的是数的编号(下标)
    //因为头尾指针都是head,tail,所以两个队列是并行的.
    //换句话说,两个队列中的值一一对应.
    		q1[++tail]=f[i];
    		q2[tail]=i;
    //把当前代价和不选的数的编号分别入队.
        }
        for(int i=n-k;i<=n;i++)
    		cnt=min(cnt,f[i]);
    //要拿总和减去最小代价,当然是找最小值啦!
        printf("%lld
    ",sum-cnt);
        return 0;
    }
    
    
  • 相关阅读:
    移动布局---1. 移动端布局基础
    1. CSS新特性之选择器
    1. H5新增语义化标签
    POJ 3281
    poj 1986
    POJ 3728
    poj 2763
    poj 2749
    uva 11294
    LA 3713
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10322058.html
Copyright © 2011-2022 走看看