CF#783 D. Optimal Partition


题目地址:D. Optimal Partition
最简单的O(n2)的dp还是很好想的
所以比赛时重点就在想怎么优化:
1、对于当前的 a[i],如果 a[i] 是个负数:如果负数的值很小,可以考虑并入前面一个区间,且前一个区间和仍然大于0。例如 2 -1 3, 接下来的a[4] = -2;如果负数的值很大,就贪心单独拎出来,这样只比前面的结果-1。例如 1 3 2,接下来a[4] = -15。

2、如果是一个正数,肯定并入前一个区间,贪心的使这个正数可以 “拉” 起来尽可能多的负数,比如前面 2 -5 -6 然后来了个100。

3、接着第2点往后面想,感觉是找一个最左边的前缀和比当前前缀和小的位置,然后更新答案。也就是找一个最小的 j,满足 prefj < prefi 的 j,dp[i] = dp[j] + (i-j)。对于 [ j+1, i ]之间的所有数,是一段连续的为正数的,这样划分它们依旧是正的; 而如果是一段连续和为负数的,这样划分后就相当于…(比较通俗的讲)在新加入的正数 a[i] 的帮助下,联合原先连续子串和为正的把所有连续子串和为负数的子串给 “拉” 起来了

然后感觉有上分希望就直接写了个维护前缀和 pref 和其下标的递减单调栈,每次在栈中二分第一个 prefk < prefi 的地方然后更新,然后WA2。

赛后研究了下,假如我这 j 取在了一个原先连续子串和为正数的中间怎么办?比如 …,1, 2, -10, -20, 100,… 我这个 j 取到了-20的位置,把100捞过来了,但是-10,-20没数字 “拉” 了。而如果我取右边的一个前缀和依旧小于当前前缀和的位置,100留给原先的子串,就可以更优。

数据:
1
7
-3 -3 9 1 -10 -2 4
原来的输出: 3
Correct : 5

CF题解 :查询 1~i 中间最优的位置, 因为 dp[i] = dp[j] + (i - j) = ( dp[j] - j ) + i,所以就是查这个最大的 dp[j] - j;但是怎么满足前缀和比它小这一点呢?把前缀和当下标,也就是 tree[ pref[ j ] ] = dp[ j ] - j,每次查询数组tree 1 ~ prefi 之间的最大值就行 ,用线段树。哦对了,你还要对前缀和离散化。

假贪心思路代码:CF-Submission
AC丑代码:CF-Submission

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值