来了来了。


题目:

给你n个数,你一次操作可以把某一个数-1(可以减为负数),你的目标是使任意的k个数严格小于它旁边的两个数(第一个数只用严格小于第二个数,第n个数只用严格小于第n-1个数),问最少需要几次操作。k是不确定的,请输出1<=k<=n/2(向上取整)时的答案。

输入格式:

第一行一个正整数n

第二行n个正整数ai

输出格式:

一行 1<=k<=n/2 个数,第i个数代表k=i时的答案

数据范围:

1 ≤ n ≤ 5000

1 ≤ ai ≤ 100000

输入 #1复制

5
1 1 1 1 1
输出 #1复制

1 2 2 
输入 #2复制

3
1 2 3
输出 #2复制

0 2 

思路:

看到这道题的第一眼,我想到了一道题,2018noipD1T1铺设道路(链接:https://www.luogu.com.cn/problem/P5019),看起来十分相似,于是这道题想用朴素的贪心写,结果果然不对,两道题的区别还是很大,贪心的正确性无法保证,所以还是回来老老实实的写动归。

我们设定一个三维数组f,f[i][j][0]表示前i座山,修建j座房子,且第i座山没有建房子的代价,f[i][j][1]表示前i座山,修建j座房子,且第i座山建有房子的代价。

通过简单的模拟我们可以得到,(1)f[i][j][0]会从f[i-1][j][0](直接从前一个状态搬过来,前一座山和这座山都不建房子,抹油代价)和f[i-1][j][1](前一座山已经建了房子,那么就要使这座山的高度低于前一座山的高度,代价为max(0,a[i]-a[i-1]+1),有0是因为可能这座山的高度原来就低于前一座山的高度)转移过来,转移方程为:f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]+max(0,a[i]-a[i-1]+1))   (2)f[i][j][1]的处理要比f[i][j][0]的处理相对复杂,在此我们明确一个观点,相邻的两座山不可能都建房子,并且在考虑这座山是否建房子的时候,可以只考虑这座山之前的状态,而不去考虑这座山之后的状态,这座山之后的状态我们可以在之后再处理,因此,f[i][j][1]可以从f[i-2][j-1][0]转移过来,因为第i-2座山没有建房子,所以第i-1座山的高度没有变化,代价为max(0,a[i]-a[i-1]+1)。f[i][j][1]同样可以从f[i-2][j-1][1]转移过来,因为第i-2座山已经建有房子,所以第i-1座山的高度可能会有变化,因此,总代价为:max(0,a[i-1]-(a[i-2],a[i])+1)(大家思考一下,为什么这里总代价不是:max(0,a[i-1]-min(0,a[i-1]-a[i-2]+1)-a[i]+1)) 答案(先思考再看答案):因为第i-1座山的高度一定比第i-2和i座山低,而这样做只能保证第i-1座山的高度低于第i-2座山的高度,无法保证第i-1座山的高度低于第i座山的高度,因此,我们也可以改成:max(max(0,a[i-1]-a[i]+1),max(0,a[i-1]-a[i-2]+1)) 贼长)

代码:

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=5e3+,maxe=5e3+,INF=0x3f3f3f3f;
int n,m,a[maxn],f[maxn][maxn][],ans;
inline int read(){
int s=,t=;
char ch=getchar();
while(ch<''||ch>''){if(ch=='-')t=-;ch=getchar();}
while(ch>=''&&ch<='')s=s*+ch-'',ch=getchar();
return s*t;
}//朴素快读
int main(){
freopen("a.in","r",stdin);
n=read();
for(int i=;i<=n;i++)a[i]=read();
a[]=INF;
memset(f,0x3f,sizeof(f));
f[][][]=f[][][]=f[][][]=;//初始化
for(int i=;i<=n;i++){
f[i][][]=f[i-][][];
for(int j=;j<=(i+)/;j++){//这里我测了一下,不管是用floor+1还是用ceil都不行,神奇
f[i][j][]=min(f[i-][j-][]+max(,a[i-]-a[i]+),f[i-][j-][]+max(max(,a[i-]-a[i]+),max(,a[i-]-a[i-]+)));
f[i][j][]=min(f[i-][j][],f[i-][j][]+max(,a[i]-a[i-]+));
}
//cout<<floor(i/2)+1<<" "<<(i+1)/2<<endl;
}
for(int i=;i<=(n+)/;i++)cout<<min(f[n][i][],f[n][i][])<<" ";
return ;
}

嘤嘤嘤,溜了

最新文章

  1. ASP.NET MVC Model验证(四)
  2. JS事件的三种方式
  3. js中let和var定义变量的区别
  4. JQ属性和css部分测试
  5. [转]通过AngularJS directive对bootstrap日期控件的的简单包装
  6. C/C++ 跨平台交叉编译、静态库/动态库编译、MinGW、Cygwin、CodeBlocks使用原理及链接参数选项
  7. iframe获取父、子窗口的方法
  8. iOS UIView常用方法和属性
  9. ubuntu 13.10 64bit装BeyondCompare
  10. axel源码学习(0)&mdash;&mdash;程序逻辑
  11. bzoj3796
  12. Merge Two Sorted Lists 解答
  13. 【LeetCode】190. Reverse Bits
  14. 关于在linux下清屏的几种技巧(转载-备忘)
  15. Java 由浅入深GUI编程实战练习(一)
  16. 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字
  17. codeforces 804A Find Amir 思维/水题
  18. Python——pytessercat识别简单的验证码
  19. 18核心的Intel i9将在2019年夏发布
  20. webservice跨域问题

热门文章

  1. 温故知新-多线程-深入刨析CAS
  2. Android数据库框架-ORMLite
  3. Python--循环--for &amp;&amp; while
  4. Flask 蓝图(Blueprint)使用方式解析
  5. 0.1---selenium+java自动化测试进阶01---PageObject设计模式
  6. 深入理解 EF Core:EF Core 读取数据时发生了什么?
  7. unittest模块在linux报错: AttributeError: module &#39;unittest&#39; has no attribute &#39;TestRunner&#39;
  8. 利用salt stack pillar安装多组keepalived
  9. vue element安装
  10. 四层发现-UDP发现