【BZOJ 1044】[HAOI2008]木棍分割
2017-02-17 21:59
190 查看
思路:
首先二分的答案,算出切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] )%p; } printf("%d %d", ans, res); return 0; }
相关文章推荐
- bzoj1044[HAOI2008]木棍分割
- BZOJ 1044: [HAOI2008]木棍分割(二分答案+DP)
- BZOJ 1044: [HAOI2008]木棍分割 二分 dp
- 【czy系列赛】czy的后宫6 && bzoj1044 [HAOI2008]木棍分割
- BZOJ1044 [HAOI2008]木棍分割
- BZOJ_1044_[HAOI2008]木棍分割_二分答案+DP+单调队列
- 【czy系列赛】czy的后宫6 && bzoj1044 [HAOI2008]木棍分割
- 【BZOJ1044】【HAOI2008】木棍分割
- bzoj 1044 [HAOI2008]木棍分割 题解
- 1044: [HAOI2008]木棍分割 - BZOJ
- bzoj1044: [HAOI2008]木棍分割
- BZOJ1044 [HAOI2008]木棍分割
- [BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化
- 【BZOJ】1044: [HAOI2008]木棍分割(二分+dp)
- bzoj 1044: [HAOI2008]木棍分割(二分+DP)
- bzoj 1044: [HAOI2008]木棍分割【二分+dp】
- 【bzoj1044】[HAOI2008]木棍分割 二分+dp
- BZOJ1044: [HAOI2008]木棍分割
- BZOJ 1044: [HAOI2008]木棍分割|动态规划|二分答案
- [bzoj1044][HAOI2008]木棍分割