51Nod1053 最大M子段和V2 二分+DP
直接DP的话最多也只能做到\(O(nm)\),对于\(5\times 10^4\)的数据范围实在无能为力
夹克老爷提供的做法是贪心,思想大概是在调整的同时,合理构造每个选择对应的新状态,使得新状态的一些选择可以代表“反悔”当前决策
(然而我没看懂……要是我看懂了也就不会有这个做法了)
其实还有另一种可能更好理解的做法
我们不妨考虑一种类似王钦石二分的思路
可以为每段额外加上一个相同的损失,在之后求最优解时不再考虑段数的限制
不难发现这个损失越大答案的段数就会越少,损失越小段数就会越多,存在单调性
所以我们可以二分这个损失,最后一定能找到一个损失值使得在此前提下存在一种段数满足要求的解
(并不严谨的证明:显然对于一个确定的损失值,最优解的段数是一个区间,然而在损失值+1时得到的最多段数其实就是当前损失值得到的最少段数-1,换句话说这些区间可以覆盖所有可能的段数)
方便起见,可以直接求最优解前提下最少的段数,这样我们只需要找到最少段数\(\le m\)时最小的损失值即可
注意最后求最优解时得到的段数不一定恰好是\(m\),但这种情况其实无所谓,因为出现这种情况时,一定是考虑损失后多加几段最优解不变,所以不用担心
注意二分上下界取\(10^9\)是不够的,但是鉴于题目的特殊性,取所有正数的和一定够了
#include<bits/stdc++.h>
using namespace std;
const int maxn=50005;
int solve(long long);
long long f[maxn],tmp;
int n,m,a[maxn];
int main(){
scanf("%d%d",&n,&m);
int cnt=0;
long long sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
cnt+=a[i]>0;
if(a[i]>0)sum+=a[i];
}
if(cnt<=m)printf("%lld",sum);
else{
f[0]=-0x3f3f3f3f3f3f3f3fll;
long long L=-sum,R=sum;
while(L!=R){
long long M=(L+R)>>1;
if(solve(M)<=m)R=M;
else L=M+1;
}
cnt=solve(L);
printf("%lld",tmp+m*L);
}
return 0;
}
int solve(long long M){
long long ans=1ull<<63,mxf=0;
int cnt=0,mxcnt=0,anscnt=0;
for(int i=1;i<=n;i++){
f[i]=max(f[i-1],mxf-M)+a[i];
if(f[i]!=f[i-1]+a[i])cnt=mxcnt+1;
else if(f[i]==mxf-M+a[i])cnt=min(cnt,mxcnt+1);
if(ans<f[i]){
ans=f[i];
anscnt=cnt;
}
else if(ans==f[i])anscnt=min(anscnt,cnt);
if(f[i]>mxf){
mxf=f[i];
mxcnt=cnt;
}
else if(f[i]==mxf)mxcnt=min(mxcnt,cnt);
}
tmp=ans;
return anscnt;
}
51Nod1053 最大M子段和V2 二分+DP的更多相关文章
- 51nod1053 最大M子段和 V2
$n \leq 50000$的序列,问选不超过$m \leq 50000$个区间使得和最大. 如果正数区间总数比$m$小那肯定全选.否则有两种方式减少区间数量:丢掉一个正区间:补一个负区间连接两个正区 ...
- 「学习笔记」wqs二分/dp凸优化
[学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...
- 二分+DP HDU 3433 A Task Process
HDU 3433 A Task Process Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- hdu 3433 A Task Process 二分+dp
A Task Process Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- 2018.10.24 NOIP模拟 小 C 的数组(二分+dp)
传送门 考试自己yyyyyy的乱搞的没过大样例二分+dp二分+dp二分+dp过了606060把我自己都吓到了! 这么说来乱搞跟被卡常的正解比只少101010分? 那我考场不打其他暴力想正解血亏啊. 正 ...
- 【bzoj1044】[HAOI2008]木棍分割 二分+dp
题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且 ...
- Luogu P2511 [HAOI2008]木棍分割 二分+DP
思路:二分+DP 提交:3次 错因:二分写萎了,$cnt$记录段数但没有初始化成$1$,$m$切的次数没有$+1$ 思路: 先二分答案,不提: 然后有个很$naive$的$DP$: 设$f[i][j] ...
- 洛谷$P4322\ [JSOI2016]$最佳团体 二分+$dp$
正解:二分+$dp$ 解题报告: 传送门$QwQ$ 这题长得好套路嗷,,,就一看就看出来是个$01$分数规划+树形$dp$嘛$QwQ$. 考虑现在二分的值为$mid$,若$mid\leq as$,则有 ...
- $bzoj3872\ [Poi2014]\ Ant\ colony$ 二分+$dp$
正解:二分+$dp$ 解题报告: 传送门$QwQ$ 一年过去了依然没有头绪,,,$gql$的$NOIp$必将惨败了$kk$. 考虑倒推,因为知道知道除数和答案,所以可以推出被除数的范围,然后一路推到叶 ...
随机推荐
- [Swift实际操作]七、常见概念-(10)使用UserDefaults和归档方式存取用户数据实际操作
在项目开发之中,你会经常需要将一些数据存储在本地,以便记录用户生产的数据或操作习惯.在项目文件夹上带点击鼠标右键.弹出右键菜单.本文将为你演示,存储用户数据的两种常用方式. 选择菜单中的创建新文件选项 ...
- 用 TensorFlow 实现 SVM 分类问题
这篇文章解释了底部链接的代码. 问题描述  如上图所示,有一些点位于单位正方形内,并做好了标记.要求找到一条线,作为分类的标准.这些点的数据在 inearly_separable_data.csv ...
- iOS-消除CocoaPods内容警告
前言 2018年2月26日 农历正月十一 星期一 今天就想更新下博客,内容不多,心情复杂: 突然想吟诗一首: 其实,我是一个善良的人: 其实,我是一枚... 算了,还是说正事吧 消除CocoaPods ...
- JSON 字符串转换为JavaScript 对象.JSON.parse()和JSON.stringify()
使用 JavaScript 内置函数 JSON.parse() 将字符串转换为 JavaScript 对象: var text = '{ "sites" : [' + '{ &qu ...
- Xpath string()提取多个子节点中的文本
<div> <ul class="show"> <li>275万购昌平邻铁三居 总价20万买一居</li> <li>00 ...
- 【数组】kSum问题
一.2Sum 思路1: 首先对数组排序.不过由于最后返回两个数字的索引,所以需要事先对数据进行备份.然后采用2个指针l和r,分别从左端和右端向中间运动:当l和r位置的两个数字之和小于目标数字targe ...
- Android 开发工具类 25_getJSON
获取 JSON 数据并解析 import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; im ...
- Android 开发工具类 07_ScreenUtils
获得屏幕相关的辅助类: 1.获得屏幕高度: 2.获得屏幕宽度: 3.获得状态栏的高度: 4.获取当前屏幕截图,包含状态栏: 5.获取当前屏幕截图,不包含状态栏. import android.app. ...
- C/C++ -- Gui编程 -- Qt库的使用 -- 使用自定义类
1.新建空Qt工程 2.新建C++类HelloQt 3.新建ui文件,添加部件,重命名主窗体(对话框)类名HelloQt,构建生成ui头文件 4.修改头文件helloqt.h #ifndef HELL ...
- Spring4.x所有Maven依赖
Spring4.x所有Maven依赖 定义Spring版本号 1 <properties> 2 <org.springframework.version>4.3.7.RELEA ...