1044: [HAOI2008]木棍分割

二分答案限制最大的多少,然后再DP一下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
const int Dollar1 = 10007;
const int MAXN = 50010;
inline int up(int x) { return x -= Dollar1, x + (x >> 31 & Dollar1); }
inline int down(const int x) { return x + (x >> 31 & Dollar1); }
int li[MAXN], n, m;
int solve(int x) {
    int cnt = 0, now = 0;
    for (int i = 1; i <= n; ++i) {
        if (now + li[i] > x) {
            now = 0;
            ++cnt;
        }
        now += li[i];
    }
    return cnt + !!now;
}
int f[2][MAXN];
int main() {
    scanf("%d%d", &n, &m); ++m;
    int l = 1, r = 50000000, ans = 0;
    for (int i = 1; i <= n; ++i) scanf("%d", li + i), l = std::max(l, li[i]);
    while (l <= r) {
        int mid = l + r >> 1;
        if (solve(mid) <= m) r = mid - 1, ans = mid;
        else l = mid + 1;
    }
    printf("%d ", ans);
    int now = 1, lst = 0;
    f[now][0] = 1;
    int Ans = 0;
    for (int T = 1; T <= m; ++T) {
        std::swap(now, lst);
        memset(f[now], 0, sizeof f[now]);
        int lcur = 0, nx = 0, cnt = f[lst][0];
        for (int j = 1; j <= n; ++j) {
            nx += li[j]; 
            while (nx > ans) {
                cnt = down(cnt - f[lst][lcur]);
                nx -= li[++lcur];
            }
            if (lcur < j) f[now][j] = cnt;
            // printf("%d : %d %d %d\n", j, nx, lcur, cnt);
            cnt = up(cnt + f[lst][j]);
        }
//      for (int j = 0; j <= n; ++j)
//          printf("%d ", f[now][j]);
//      putchar(10);
        Ans = up(Ans + f[now][n]);
    }
    printf("%d\n", Ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/daklqw/p/10361531.html