bzoj 1044 [HAOI2008]木棍分割 二分答案+dp
题面
解法
第一问直接二分答案,第二问简单dp
注意空间问题,要用滚动数组
时间复杂度:\(O(nm)\)
代码
#include <bits/stdc++.h>
#define Mod 10007
#define N 100010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
int n, m, a[N], s[N], p[N], f[N], sum[N];
bool check(int mid) {
int sum = 0, tot = 0;
for (int i = 1; i <= n; i++)
if (sum + a[i] > mid) tot++, sum = a[i];
else sum += a[i];
return tot <= m;
}
int calc() {
int l = 0, r = 0, ret = 0;
for (int i = 1; i <= n; i++)
r += a[i], chkmax(l, a[i]);
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) ret = mid, r = mid - 1;
else l = mid + 1;
}
return ret;
}
int getpos(int x, int sum) {
int l = 0, r = x, ans = x;
while (l <= r) {
int mid = (l + r) >> 1;
if (s[x] - s[mid] <= sum) ans = mid, r = mid - 1;
else l = mid + 1;
}
return ans;
}
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++)
read(a[i]), s[i] = s[i - 1] + a[i];
int ans1 = calc(), ans2 = 0;
for (int i = 1; i <= n; i++) p[i] = getpos(i, ans1);
fill(sum, sum + n + 1, 1);
for (int j = 1; j <= m + 1; j++) {
for (int i = 1; i <= n; i++) f[i] = (sum[i - 1] - sum[p[i] - 1] + Mod) % Mod;
sum[0] = 0;
for (int i = 1; i <= n; i++) sum[i] = (sum[i - 1] + f[i]) % Mod;
ans2 = (ans2 + f[n]) % Mod;
}
cout << ans1 << ' ' << ans2 << "\n";
return 0;
}