51Nod1053 最大M子段和V2 二分+DP
2018-07-24 21:25
239 查看
直接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
- 51nod 1053 最大M子段和 V2 (链表 对经典dp进行优化)
- 51nod 最大M子段和 V1,V2,V3 dp 贪心 heap(bzoj2288)
- HAUT 1266 最大子段和(类似DP)(河南工业大学2017校赛)
- 基础DP - 循环数组最大子段和
- codeforces 788A Functions again(dp之最大子段和)【模板】
- NOJ 2045 罗马PK (线性dp 最大连续子段和)
- hpu 1082: 循环数组最大子段和 [DP]
- POJ 2479 最大子段和dp
- 最大子矩阵问题;枚举行的组合,然后利用一维最大子段和的DP算法;
- HAUT 1266 最大子段和(类似DP)(河南工业大学2017校赛)
- 51nod 1254 最大子段和 V2 ——单调栈
- 51Nod-1053-最大M子段和 V2
- 51nod 1050 循环数组最大子段和(DP)
- zoj 1074 最大子段和的推广 dp
- 循环数组最大子段和(DP)
- hdu 5586 Sum【dp最大子段和】
- [dp][二分答案]最大正方形
- HAUT 1266 最大子段和(类似DP)(河南工业大学2017校赛)
- hdu 1024 Max Sum Plus Plus(dp && 最大m子段和)