dp容易想到,但没法进一步优化了。

  考虑贪心,每次选出价值最大的物品。但这显然是不对的因为会影响其他物品的选择。

  于是考虑加上反悔操作。每次选出一个物品后,将其相邻两物品删除,再将原物品价值变为相邻两物品价值和-原物品价值。这样如果再次选择该物品就可以达到改为选择相邻两物品的效果。并且最优方案中相邻两物品一定要么都选要么都不选,否则不如选择原物品。

  这种带反悔的贪心策略似乎类似地在网络流算法中出现,应该是一个比较普遍的做法,然而并不会证。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 200010
int n,m,a[N],pre[N],nxt[N],ans;
bool flag[N];
struct data
{
int i,x;
bool operator <(const data&a) const
{
return x<a.x;
}
};
priority_queue<data> q;
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj2151.in","r",stdin);
freopen("bzoj2151.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
if (m>n/) {cout<<"Error!";return ;}
for (int i=;i<=n;i++) a[i]=read(),q.push((data){i,a[i]});
for (int i=;i<n;i++) nxt[i]=i+;
for (int i=;i<=n;i++) pre[i]=i-;
pre[]=n,nxt[n]=;
for (int i=;i<=m;i++)
{
while (flag[q.top().i]) q.pop();
data t=q.top();q.pop();
ans+=t.x;
int x=pre[t.i],y=nxt[t.i];
a[t.i]=a[x]+a[y]-a[t.i];
q.push((data){t.i,a[t.i]});
flag[x]=flag[y]=;
nxt[pre[x]]=t.i,pre[t.i]=pre[x];
pre[nxt[y]]=t.i,nxt[t.i]=nxt[y];
}
cout<<ans;
return ;
}

  不过dp真的没救了吗?看到这个恰好选k个非常容易让人联想到wqs二分。于是二分多选一个数的代价,跑正常的dp,就过掉了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 200010
#define inf 2000000010
int n,m,a[N],f[N][][],g[N][][],ans;
void chkmax(int &x,int &y,int a,int b)
{
if (a>x||a==x&&b<y) x=a,y=b;
}
bool check(int k)
{
memset(f,,sizeof(f)),memset(g,,sizeof(g));
f[][][]=a[]+k,g[][][]=;
f[][][]=f[][][]=-inf;
for (int i=;i<=n;i++)
{
f[i][][]=f[i-][][]+a[i]+k,g[i][][]=g[i-][][]+;
if (i<n) f[i][][]=f[i-][][]+a[i]+k,g[i][][]=g[i-][][]+;
if (f[i-][][]>f[i-][][]||f[i-][][]==f[i-][][]&&g[i-][][]<g[i-][][]) f[i][][]=f[i-][][],g[i][][]=g[i-][][];
else f[i][][]=f[i-][][],g[i][][]=g[i-][][];
if (f[i-][][]>f[i-][][]||f[i-][][]==f[i-][][]&&g[i-][][]<g[i-][][]) f[i][][]=f[i-][][],g[i][][]=g[i-][][];
else f[i][][]=f[i-][][],g[i][][]=g[i-][][];
}
int x=f[n][][],y=g[n][][];
chkmax(x,y,f[n][][],g[n][][]);
chkmax(x,y,f[n][][],g[n][][]);
chkmax(x,y,f[n][][],g[n][][]);
if (y<=m) {ans=x-m*k;return ;}
else return ;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("force.in","r",stdin);
freopen("force.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
if (m>n/) {cout<<"Error!";return ;}
for (int i=;i<=n;i++) a[i]=read();
int l=-,r=;
while (l<=r)
{
int mid=(l+r)/;
if (check(mid)) l=mid+;
else r=mid-;
}
cout<<ans;
return ;
}

BZOJ2151 种树(贪心+堆+链表/wqs二分+动态规划)的更多相关文章

  1. BZOJ_2151_种树_贪心+堆+链表

    BZOJ_2151_种树_贪心+堆 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编 ...

  2. bzoj2151 种树 双向链表+堆

    2151: 种树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1151  Solved: 613[Submit][Status][Discuss] ...

  3. [bzoj2288][pojChallenge]生日礼物【贪心+堆+链表】

    题目描述 ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, -, AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物. 自然地,ftiasch想要知 ...

  4. [luogu3620][APIO/CTSC 2007]数据备份【贪心+堆+链表】

    题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...

  5. [BZOJ2151] 种树 贪心

    2151: 种树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1151  Solved: 613[Submit][Status][Discuss] ...

  6. BZOJ 2288: 【POJ Challenge】生日礼物 贪心 + 堆 + 链表

    好像是模拟费用流 Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r" ...

  7. [BZOJ2288&BZOJ1150]一类堆+链表+贪心问题

    今天我们来介绍一系列比较经典的堆+链表问题.这类问题的特点是用堆选取最优解,并且通过一些加减操作来实现"反悔". 在看题之前,我们先来介绍一个神器:手写堆. 手写堆的一大好处就是可 ...

  8. BZOJ5252 八省联考2018林克卡特树(动态规划+wqs二分)

    假设已经linkcut完了树,答案显然是树的直径.那么考虑这条直径在原树中是怎样的.容易想到其是由原树中恰好k+1条点不相交的链(包括单个点)拼接而成的.因为这样的链显然可以通过linkcut拼接起来 ...

  9. WQS二分题集

    WQS二分,一种优化一类特殊DP的方法. 很多最优化问题都是形如“一堆物品,取与不取之间有限制.现在规定只取k个,最大/小化总收益”. 这类问题最自然的想法是:设f[i][j]表示前i个取j个的最大收 ...

随机推荐

  1. 【SQLSERVER】如何设置权限用户

    一.设置权限用户的意义 SQLSERVER 数据库有两个登录方式,一个是 Windows 身份验证方式 ,另一个是 SQLSERVER 身份验证方式(sa用户): 1, Windows 身份验证方式, ...

  2. C# 调用webserver 出现:未能从程序集“jgd3jufm, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”中加载类型

    一般都是 用的动态调用webserver,然后这次用的是固定的 首先 最后 实例化改接口,然后直接传值调用

  3. Qt-QML-关于两个平级的qml文件中的函数调用问题

    这几天还在继续搞我的QML,感悟就QML是坑的同时,也是一门很号的语言,用于快速搭界面是很好的.那么,这几天, 遇到一个问题,在下用一个框框画一下,希望可以理解 抽象派,解释一下,QML1和QML3是 ...

  4. 自己来编写一份 Python 脚本 第一版

    解决问题 我们已经探索了 Python 语言中的许多部分,现在我们将通过设计并编写一款程序来了解如何把这些部分组合到一起.这些程序一定是能做到一些有用的事情.这节的Python教程就是教大家方法去学习 ...

  5. Java注解的基本原理

    注解的本质就是一个继承了Annotation接口的接口,一个注解准确意义上来说,只不过是一种特殊注释而已,如果没有解析他的代码,他可能连注释都不如. 解析一个类或者方法的注解往往有两种形式,一种是编译 ...

  6. 51单片机实现定时器00H-FFH、定时器000-255

    #include< reg51.h> #define uint unsigned int #define uchar unsigned char sfr P0M0 = 0x94; sfr ...

  7. 1. 两数之和【Leetcode中国,by java】

    给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], target ...

  8. Java 消息对列

    ActiveMQ入门实例   1.下载ActiveMQ 去官方网站下载:http://activemq.apache.org/ 2.运行ActiveMQ 解压缩apache-activemq-5.5. ...

  9. 【转】MMO即时战斗:技能实现

    转自 http://blog.csdn.net/cyblueboy83/article/details/41628743 一.前言 基本所有MMO游戏无论是回合制.策略类.即时战斗等等类型都需要有相应 ...

  10. 凸包算法(Graham扫描法)详解

    先说下基础知识,不然不好理解后面的东西 两向量的X乘p1(x1,y1),p2(x2,y2) p1Xp2如果小于零则说明  p1在p2的逆时针方向 如果大于零则说明 p1在p2的顺时针方向 struct ...