首页 > 学院 > 开发设计 > 正文

【BZOJ 1044】[HAOI2008]木棍分割

2019-11-08 03:04:50
字体:
来源:转载
供稿:网友

思路:

首先二分的答案,算出切m下,最长的一段的最短值。 用动态规划求方案数。 设f[i][j]表示切了i次,使用到了前j个木段的方案数。 状态转移方程: f[i][j]=∑f[i−1][k]→(1≤k≤j−1)(sum[j]−sum[k]≤ans) 对于初始的条件,显然有f[0][1]=1 不难发现,k是随着j的增长递增的,所以用two pointer维护即可。 对于空间,第一维的显然可以滚掉。

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 50010;const int p = 10007; int n, m, sm, mx;int val[maxn], sum[maxn];int f[2][maxn];bool check(int x){ int res = 0, tmp = 0; for(int i = 1; i <= n; i ++){ if(tmp + val[i] <= x) tmp += val[i]; else tmp = val[i], res ++; } return res <= m;}int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%d", &val[i]), sm += val[i], mx = max(mx, val[i]); for(int i = 1; i <= n; i ++) sum[i] = sum[i-1] + val[i]; int l = mx, r = sm, ans = 0; while(l <= r){ int mid = (l+r) >> 1; if(check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } int now = 0, res = 0; for(int i = 1; sum[i] <= ans; i ++) f[now][i] = 1; for(int i = 1; i <= m; i ++){ int ll = 0, rr = 0, x = 0; now ^= 1; for(int j = 1; j <= n; j ++){ while(rr < j-1) x = ((x+f[now^1][++rr])%p+p)%p; while(sum[j]-sum[ll] > ans) x = ((x-f[now^1][ll++])%p+p)%p; f[now][j] = x; } res = (res+f[now][n])%p; } PRintf("%d %d", ans, res); return 0;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表