[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;
cnt = up(cnt + f[lst][j]);
}
Ans = up(Ans + f[now][n]);
}
printf("%d\n", Ans);
return 0;
}