HDU 6606 Distribution of books — 2019第三场杭电多校 1004题

题意

大概说一下我理解的题意。。。

给你一个长度为 n n n的序列,你可以随意抛弃一些后缀数字,但必须保证序列至少包含 k k k个数字。

问将这个序列分成连续 k k k段后,问段的权值和最大值最小为多少?

思路

二分,dp验证,线段树优化

二分答案, d p [ i ] dp[i] dp[i]表示前 i i i个数能分成多少段

转移: d p [ i ] = ∑ m a x ( d p [ j ] + 1 ) [ s u m [ i ] − s u m [ j ] ≤ x ] dp[i] = \sum_{max}(dp[j]+1)[sum[i]-sum[j]\le x] dp[i]=max(dp[j]+1)[sum[i]sum[j]x]

权值线段树维护前缀和值对应的最大 d p dp dp值,支持单点更新,区间查询即可。


比赛时最初在想 d p dp dp,因为之前刚做过HDU - 1024这个最大 m m m子段和,然后自闭了好久不会优化复杂度。。

后来队友说了句二分,感觉好有道理。。。。

经过一段时间的自闭,感觉好像知道怎么写了,想到了dp验证,线段树优化。。。but我没想到权值线段树,我想成了每个位置维护一个前缀和值和dp权值。。。。然后gg了,比赛代码如下(不过我当时dp写法不一样,思路差不多

在这里插入图片描述

AC_Code

vector<LL> vs;
int ok(LL x) {
    vs.eb(-1e18);
    for(int i = 1; i <= n; ++i) {
        res[i] = res[i-1] + ar[i];
        vs.eb(res[i]), vs.eb(res[i] - x);
    }
    my_unique(vs);
    build(1, vs.size(), 1);
    int flag = 0;
    for(int i = 1; i <= n; ++i) {
        if(res[i] <= x) dp[i] = 1;
        else dp[i] = 0;
        int tmp = lower_bound(all(vs), res[i]) - vs.begin();
        int las = lower_bound(all(vs), res[i] - x) - vs.begin();
        int ret = query(las, vs.size(), 1, vs.size(), 1);
        if(ret) dp[i] = big(ret + 1, dp[i]);
        update(tmp, dp[i], 1, vs.size(), 1);
        flag = max(flag, dp[i]);
    }
    vs.clear();
    return flag >= k;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值