给出一个 1 ∼ N 的序列 A ( A 1 , A 2 , ..., A N ) 。你每次可以将两个相邻的元素合并,合并后的元素权值即为 这两个元素的权值之和。求将 A 变为一个非降序列,最少需要多少步操作。

Input

输入的第一行一个整数 N ( N ≤ 5000) 。 
接下来一行 N 个整数,描述序列 A 。保证序列 A 中的每个元素的值不超过 1000 。

Output

输出一行一个整数,表示最少的操作数。

 
题解:
区间dp真的难,(。・∀・)ノ゙嗨!
好了,设dp[i][j]表示从区间把前j个数,把区间i~j合并后满足单调的元素数量,我们可以考虑,统计一个前缀和sum,然后枚举
三个端点i,j,k,我们是想把i~j压缩成一个数,然后k在i之前,找到元素数量最少的,进行转移,转移条件 是sum[i]-sum[k-1]<=sum[j]-sum[i]
代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
const int MAXN=;
using namespace std;
int dp[MAXN][MAXN],sum[MAXN],ans=-; void cl(){
memset(dp,,sizeof(dp));
memset(sum,,sizeof(sum));
} int main(){
cl();
int n;
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&sum[i]);
sum[i]+=sum[i-];
}
for(int i=;i<=n;i++){
dp[i][]=;
int k=i,res=-;
for(int j=i+;j<=n;j++){
while(k&&sum[i]-sum[k-]<=sum[j]-sum[i]) res=max(res,dp[i][k--]);
if(res==-) dp[j][i+]=-;
else dp[j][i+]=max(dp[j][i+],res+);
//printf("i=%d j=%d k=%d\n",i,j,k);
}
}
for(int i=;i<=n;i++) ans=max(ans,dp[n][i]);
if(ans==-) printf("-1");
else printf("%d",n-ans);
}

最新文章

  1. Linux2.6内核协议栈系列--TCP协议2.接收
  2. Azure 带宽
  3. List集合对象根据字段排序
  4. Difference Between Vector and Deque in C++
  5. pinyin4j使用示例
  6. URL特殊字符需转义
  7. margin-top塌陷
  8. vue的风格指南(必要的)
  9. vs2015官方下载链接
  10. 廖雪峰Java9正则表达式-2正则表达式进阶-3分组匹配
  11. 【LOJ#6280】数列分块4
  12. Codeforces 707E Garlands
  13. django admin后台设置
  14. 【Redis】使用Jedis操作Redis
  15. CentOS 7 系统root用户忘记密码的重置方法
  16. 在kali linux之下安装wps之后 报错字体缺失
  17. 了解dto概念,什么是DTO
  18. 日志工具——log4j
  19. react项目跨域问题
  20. Ceph添加/删除Mon(ceph.conf)

热门文章

  1. CentOS 7 下网络无法访问 Failed to start LSB: Bring up/.
  2. Sublime Text 实用方法
  3. ViewGroup和View
  4. 加入百度地图遇到 framework not found BaiduMapAPI***
  5. Spring入门(十二):Spring MVC使用讲解
  6. 为什么Kubernetes使用Pod作为最小调度单元
  7. 数据库占用CPU过高,性能分析与调优
  8. Redis数据库之服务器主从配置
  9. 升级@Scheduled-分布式定时任务
  10. mybatis collection和association使用区别