[BZOJ 1044] [HAOI2008] 木棍分割 【二分 + DP】
题目链接:BZOJ 1044
第一问是一个十分显然的二分,贪心Check(),很容易就能求出最小的最大长度 Len 。
第二问求方案总数,使用 DP 求解。
使用前缀和,令 Sum[i] 为前 i 根木棍的长度和。
令 f[i][j] 为前 i 根木棍中切 j 刀,并且满足最长长度不超过 j 的方案数,那么:
状态转移方程: f[i][j] = Σ f[k][j-1] ((1 <= k <= i-1) && (Sum[i] - Sum[k] <= Len))
这样的空间复杂度为 O(nm) ,时间复杂度为 O(n^2 m) 。显然都超出了限制。
下面我们考虑 DP 的优化。
1) 对于空间的优化。
这个比较显然,由于当前的 f[][j] 只与 f[][j-1] 有关,所以可以用滚动数组来实现。
f[i][Now] 代替了 f[i][j] , f[i][Now^1] 代替了 f[i][j-1] 。为了方便,我们把 f[][Now^1] 叫做 f[][Last] 。
这样空间复杂度为 O(n) 。满足空间限制。
2) 对于时间的优化。
考虑优化状态转移的过程。
对于 f[i][Now] ,其实是 f[mink][Last]...f[i-1][Last] 这一段 f[k][Last] 的和,mink 是满足 Sum[i] - Sum[k] <= Len 的最小的 k ,那么,对于从 1 到 n 枚举的 i ,相对应的 mink 也一定是非递减的(因为 Sum[i] 是递增的)。我们记录下 f[1][Last]...f[i-1][Last] 的和 Sumf ,mink 初始设为 1,每次对于 i 将 mink 向后推移,推移的同时将被舍弃的 p 对应的 f[p][Last] 从 Sumf 中减去。那么 f[i][Now] 就是 Sumf 的值。
这样时间复杂度为 O(nm) 。满足时间限制。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; const int MaxN = 50000 + 5, Mod = 10007; int n, m, Len, MaxLen, Ans, Sumf;
int A[MaxN], Sum[MaxN], f[MaxN][2]; inline int gmax(int a, int b) {
return a > b ? a : b;
}
inline int gmin(int a, int b) {
return a < b ? a : b;
} bool Check(int x) {
if (x < MaxLen) return false;
int Add = 0, Cut = 0;
for (int i = 1; i <= n; i++) {
if (Add + A[i] > x) {
Cut++;
if (Cut > m) return false;
Add = 0;
}
Add += A[i];
}
return true;
} int main()
{
scanf("%d%d", &n, &m);
MaxLen = 0;
memset(Sum, 0, sizeof(Sum));
for (int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
MaxLen = gmax(MaxLen, A[i]);
Sum[i] = Sum[i - 1] + A[i];
}
int l = 0, r = 50000000, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (Check(mid)) r = mid - 1;
else l = mid + 1;
}
Len = r + 1;
memset(f, 0, sizeof(f));
Ans = 0;
int Now = 0, Last = 1, Mink;
for (int i = 0; i <= m; i++) {
Sumf = 0;
Mink = 1;
for (int j = 1; j <= n; j++) {
if (i == 0) {
if (Sum[j] <= Len) f[j][Now] = 1;
else f[j][Now] = 0;
}
else {
while (Mink < j && Sum[j] - Sum[Mink] > Len) {
Sumf -= f[Mink][Last];
Sumf = (Sumf + Mod) % Mod;
++Mink;
}
f[j][Now] = Sumf;
}
Sumf += f[j][Last];
Sumf %= Mod;
}
Ans += f[n][Now];
Ans %= Mod;
Now ^= 1;
Last = Now ^ 1;
}
printf("%d %d\n", Len, Ans);
return 0;
}
[BZOJ 1044] [HAOI2008] 木棍分割 【二分 + DP】的更多相关文章
- BZOJ 1044: [HAOI2008]木棍分割(二分答案 + dp)
第一问可以二分答案,然后贪心来判断. 第二问dp, dp[i][j] = sigma(dp[k][j - 1]) (1 <= k <i, sum[i] - sum[k] <= ans ...
- BZOJ 1044: [HAOI2008]木棍分割
Description 求 \(n\) 根木棍长度为 \(L\) ,分成 \(m\) 份,使最长长度最短,并求出方案数. Sol 二分+DP. 二分很简单啊,然后就是方案数的求法. 状态就是 \(f[ ...
- 【bzoj1044】[HAOI2008]木棍分割 二分+dp
题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且 ...
- Luogu P2511 [HAOI2008]木棍分割 二分+DP
思路:二分+DP 提交:3次 错因:二分写萎了,$cnt$记录段数但没有初始化成$1$,$m$切的次数没有$+1$ 思路: 先二分答案,不提: 然后有个很$naive$的$DP$: 设$f[i][j] ...
- 【BZOJ】1044: [HAOI2008]木棍分割 二分+区间DP
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1044 Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, ...
- bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1044 [题意] n根木棍拼到一起,最多可以切m刀,问切成后最大段的最小值及其方案数. ...
- bzoj 1044: [HAOI2008]木棍分割【二分+dp】
对于第一问二分然后贪心判断即可 对于第二问,设f[i][j]为已经到j为止砍了i段,转移的话从$$ f[i][j]=\sigema f[k][j-1] (s[j]-s[k-1]<=ans) 这里 ...
- BZOJ 1044: [HAOI2008]木棍分割 DP 前缀和优化
题目链接 咳咳咳,第一次没大看题解做DP 以前的我应该是这样的 哇咔咔,这tm咋做,不管了,先看个题解,再写代码 终于看懂了,卧槽咋写啊,算了还是抄吧 第一问类似于noip的那个跳房子,随便做 这里重 ...
- bzoj 1044 [HAOI2008]木棍分割——前缀和优化dp
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044 前缀和优化. 但开成long long会T.(仔细一看不用开long long) #i ...
随机推荐
- python:浅析python 中__name__ = '__main__' 的作用
有句话经典的概括了这段代码的意义: “Make a script both importable and executable” 意思就是说让你写的脚本模块既可以导入到别的模块中用,另外该模块自己也可 ...
- Spring IoC容器的设计—1—主线
IoC容器的接口设计图 下面对接口关系做一些简要的分析,可以依据以下内容来理解这张接口设计图. 从接口BeanFactory到HierarchicalBeanFactory,再到Configurabl ...
- java 设计模式之单例模式
-------Success is getting what you want, happiness is wanting what you get. java设计模式之单例模式(Singleton) ...
- ListBox复选框拓展
Toolkit的LongListMutiSelector的复选框功能,想必许多人都需要吧!然而系统本身控件ListBox虽然也有多选功能,可是外观上却缺乏复选框,选择效果只是颜色变化.于是在上一个项目 ...
- fpm打包redis3.0.7
1.安装redis tar -xf redis-3.0.7.tar.gz -C /usr/local cd /usr/local && mv redis-3.0.7 redis cd ...
- shell编程基础练习
shell作为一个人机交互的接口,在Linux中发挥着很大的作用,而shell编程则是减轻系统工程师工作的利器,这里总结一下shell编程的主要内容(趁着程序运行的空档). 本文的基本结构是shell ...
- Docker 启动失败Starting docker (via systemctl): Job for docker.service failed
Starting docker (via systemctl): Job for docker.service failed. See 'systemctl status docker.servic ...
- (转)Android Support Percent百分比布局
一.概述 周末游戏打得过猛,于是周天熬夜码代码,周一早上浑浑噩噩的发现 android-percent-support-lib-sample(https://github.com/JulienGeno ...
- Allegro中板子边框不封闭导致的z-copy无法用的问题
画一个不规则的边框,有半圆形状,导致边框不封闭,无法使用Z-COPY命令,下边是解决办法: 1 画好Outline后,选择 shape -> Compose Shape , options选项卡 ...
- Linux使用标准IO的调用函数,分3种形式实现
/*根据cp命令的格式要求,设计一个类cp的功能程序,要求使用标准IO的调用函数,分3种形式实现,字符,行,块.并注意函数功能的分层*/ #include<stdio.h> #includ ...