BZOJ 1044 HAOI 2008 木棍分割 二分 贪心 动态规划

真是心烦。。似乎一个sb用脚本拼命交30s的while(1)程序卡评测。。这种缺智商的大抵也就会卡oj了。明明有80s的250s的去卡30s的

第一问 二分贪心即可得到答案max_cut。
第二问 令 f[i][j] 表示前i根切j次的方案数。那么显然有

f[i][j]=f[k][j1](a[k+1]++a[i]max_cut)

首先可以滚动数组。
然后发现合法区间的两端点始终向右移动,预处理每层dp的前缀和可以将复杂度优化到 O(nm)
如何维护?双端队列。
不过考察代码能力的时候到了。
一些速度不忍直视(7s)。。
一些速度还好(2s)。。
还有因为取模太慢了。。

#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
int read() {
    int s = 0, f = 1; char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
    return s * f;
}
int main() {
    const int N = 50001, mod = 10007;
    static int sum[N], a[N], f[N], sf[N], pre[N], q[N];
    int i, j, l = 2, r, t, s, mid, ans = 0, last = 1, max_cut, n = read(), m = read();
    FOR(i,1,n) {
        sum[i] = sum[i - 1] + (a[i] = read());
        if (a[i] > l) l = a[i];
    }
    l -= 1, r = sum[n];
    while (l <= r) {
        mid = l + r >> 1; t = s = 0;
        FOR(i,1,n) {
            s += a[i];
            if (s > mid) ++t, s = a[i];
            if (t > m) i = 79999;
            else if (a[i] > mid) i = 79999;
        }
        if (i != 80000) max_cut = mid, r = mid - 1;
        else l = mid + 1;
    }
    FOR(i,1,n) {
        while (sum[i] - sum[last] > max_cut) ++last;
        pre[i] = last - 1;
    }
    for(i = 1; i <= n && sum[i] <= max_cut; ++i) f[i] = 1;
    FOR(i,1,n) sf[i] = (sf[i - 1] + f[i]) % mod;
    FOR(i,1,m) {
        FOR(j,1,n) f[j] = (sf[j - 1] - sf[pre[j]]) % mod;
        FOR(j,1,n) sf[j] = sf[j - 1] + f[j];
        ans += f[n]; if (ans > mod) ans -= mod;
    }
    printf("%d %d", max_cut, ans);
    return 0;
}

1044: [HAOI2008]木棍分割

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 2611 Solved: 967
[Submit][Status][Discuss]

Description

有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。。。

Input

输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍的长度.

Output

输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

Sample Input

3 2

1

1

10

Sample Output

10 2

HINT

两种砍的方法: (1)(1)(10)和(1 1)(10)

数据范围

n<=50000, 0<=m<=min(n-1,1000).

1<=Li<=1000.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值