[HAOI2008]木棍分割
Posted zzy2005
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2008]木棍分割相关的知识,希望对你有一定的参考价值。
题解
第一问应该一眼就可以看出二分+贪心
问题是第二问。
可以想到(dp)
(f[i][j])表示前i个木棍,分成j份, 每一份都不超过ans1的方案数
(f_{i,j} =sum_{k=x}^{i-1} f_{k,j-1})
(( 第z位到第i位可以作为一段, x为最小的z ))
显然(x)满足单调,可以(O(n))求出
对于上面的dp,前缀和 就可以满足复杂度了
Code
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
inline int gi() {
RG int x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
return f ? -x : x;
}
const int N = 50010, Mod = 10007;
int n, m, L[N];
bool check(int x) {
int cnt = 0, s = 0;
for (int i = 1; i <= n; i++) {
if (L[i] > x) return 0;
if (L[i] + s <= x) s += L[i];
else cnt++, s = L[i];
}
return cnt <= m;
}
int f[N], g[N], lf[N];
int main() {
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
n = gi(), m = gi();
int l = 0, r = 0;
for (int i = 1; i <= n; i++) L[i] = gi(), r += L[i];
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid-1;
else l = mid+1;
}
int ans1 = r+1, ans2 = 0;
int s = 0, w = 0;
m++;
s = L[1];
for (int i = 2; i <= n; i++) {
while (s+L[i] > ans1) s -= L[++w];
s += L[i];
lf[i] = w;
}
for (int i = 0; i <= n; i++)
g[i] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++)
f[j] = (g[j-1]-g[lf[j]-1]+Mod)%Mod;
g[0] = 0;
for (int j = 1; j <= n; j++)
g[j] = (g[j-1]+f[j]) % Mod;
ans2 = (f[n]+ans2) % Mod;
}
printf("%d %d
", ans1, ans2);
return 0;
}
以上是关于[HAOI2008]木棍分割的主要内容,如果未能解决你的问题,请参考以下文章