第一问可以二分答案,然后贪心来判断.

第二问dp, dp[i][j] = sigma(dp[k][j - 1]) (1 <= k <i, sum[i] - sum[k] <= ans) dp[i][j] 表示前i根木棍切了j次最大长度<=ans的方案数。sum[i]为1~i 的木棍长度和(前缀和).明显可以用滚动数组优化.然后又会发现, 对于每个dp[i][j]求和过程中,sum[i]不变,而sum[k]是单调递增,满足的k值是一连续的区间,且满足的最小k随i变大而变大,所以可以用一个变量累计.复杂度O(nm).

-------------------------------------------------------------------------------------------------

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
 
#define rep(i, n) for(int i = 0; i < n; ++i)
#define Rep(i, l, r) for(int i = l; i <= n; ++i)
#define clr(x, c) memset(x, c, sizeof(x))
#define mod(x) ((x + 10007) %= 10007)
 
using namespace std;
 
const int maxn = 50000 + 5;
 
int n, m, ans = 0;
int sumL[maxn];
int d[maxn][2];
 
void Read() {
scanf("%d%d", &n, &m);
int t;
sumL[0] = 0;
Rep(i, 1, n) {
scanf("%d", &t);
sumL[i] = sumL[i - 1] + t;
}
}
 
bool jud(int ans) {
int cnt = m, front = 0, rear = 0;
while(rear < n) {
while(rear < n && sumL[rear + 1] - sumL[front] <= ans) rear++;
if(rear < n) {
front = rear;
if(--cnt < 0) return false;
}
}
return true;
}
 
void BS() {
int l = 0, r = sumL[n];
while(l <= r) {
int mid = (l + r) >> 1;
if(jud(mid)) { ans = mid; r = mid - 1; }
else l = mid + 1;
}
printf("%d ", ans);
}
 
void DP() {
int cur = 0, Ans = 0;
Rep(i, 1, n) d[i][cur] = sumL[i] <= ans ? 1 : 0;
d[0][0] = d[0][1] = 0;
while(m--) {
cur ^= 1;
int p = 0, sum = 0;
Rep(i, 1, n) {
while(sumL[i] - sumL[p] > ans) mod(sum -= d[p++][cur ^ 1]);
mod(d[i][cur] = sum);
mod(sum += d[i][cur ^ 1]);
}
mod(Ans += d[n][cur]);
}
printf("%d\n", Ans);
}
 
int main() {
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
Read();
BS();
DP();
return 0;
}

-------------------------------------------------------------------------------------------------

1044: [HAOI2008]木棍分割

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2095  Solved: 761
[Submit][Status][Discuss]

Description

有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007。。。

Input

输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍的长度.

Output

输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

Sample Input

3 2
1
1
10

Sample Output

10 2

HINT

两种砍的方法: (1)(1)(10)和(1 1)(10)

数据范围

n<=50000, 0<=m<=min(n-1,1000).

1<=Li<=1000.

Source

BZOJ 1044: [HAOI2008]木棍分割(二分答案 + dp)的更多相关文章

  1. BZOJ 1044 HAOI2008 木棍切割 二分答案+动态规划

    题目大意:给定n个连在一起的木棍.分成m+1段.使每段最大值最小,求最大值的最小值及最大值最小时切割的方案数 第一问水爆了--二分答案妥妥秒过 第二问就有些难度了 首先我们令f[i][j]表示用前j个 ...

  2. 【BZOJ】1044: [HAOI2008]木棍分割 二分+区间DP

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1044 Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, ...

  3. [BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化

    1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4112  Solved: 1577 [Submit][St ...

  4. [BZOJ 1044] [HAOI2008] 木棍分割 【二分 + DP】

    题目链接:BZOJ 1044 第一问是一个十分显然的二分,贪心Check(),很容易就能求出最小的最大长度 Len . 第二问求方案总数,使用 DP 求解. 使用前缀和,令 Sum[i] 为前 i 根 ...

  5. bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1044 [题意] n根木棍拼到一起,最多可以切m刀,问切成后最大段的最小值及其方案数. ...

  6. bzoj 1044: [HAOI2008]木棍分割【二分+dp】

    对于第一问二分然后贪心判断即可 对于第二问,设f[i][j]为已经到j为止砍了i段,转移的话从$$ f[i][j]=\sigema f[k][j-1] (s[j]-s[k-1]<=ans) 这里 ...

  7. BZOJ 1044: [HAOI2008]木棍分割 DP 前缀和优化

    题目链接 咳咳咳,第一次没大看题解做DP 以前的我应该是这样的 哇咔咔,这tm咋做,不管了,先看个题解,再写代码 终于看懂了,卧槽咋写啊,算了还是抄吧 第一问类似于noip的那个跳房子,随便做 这里重 ...

  8. bzoj 1044 [HAOI2008]木棍分割——前缀和优化dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044 前缀和优化. 但开成long long会T.(仔细一看不用开long long) #i ...

  9. BZOJ 1044: [HAOI2008]木棍分割

    Description 求 \(n\) 根木棍长度为 \(L\) ,分成 \(m\) 份,使最长长度最短,并求出方案数. Sol 二分+DP. 二分很简单啊,然后就是方案数的求法. 状态就是 \(f[ ...

随机推荐

  1. Codeforces 263E

    Codeforces 263E 原题 题目描述:一个\(n \times m\)的矩阵,每格有一个数,给出一个整数\(k\),定义函数\(f(x, y)\): \[f(x, y)=\sum_{i=1} ...

  2. uvalive5810 uva12368 Candles

    题意:每组数据给出n个数,每个数在1-100,问组成这些数的蜡烛的权值的最小值.权值=把选的蜡烛从大到小排列组成的数 组成方式:比如有1 3两个蜡烛 可以组成13(1和3)或4(1+3) 只有一个加号 ...

  3. poj2388---求奇数个数字的最中间的数

    #include <stdio.h> #include <stdlib.h> int cmp(const void *a,const void *b) { return (*( ...

  4. UberX及以上级别车奖励政策(优步北京第四组)

    优步北京第四组: 定义为2015年7月20日至今激活的司机(以优步后台数据显示为准) 滴滴快车单单2.5倍,注册地址:http://www.udache.com/如何注册Uber司机(全国版最新最详细 ...

  5. C++ *max_element函数找最大元素 *min_element函数找最小元素 STL算法(转)

    http://blog.sina.com.cn/s/blog_6f3a860501019z1f.html #include<iostream> #include<algorithm& ...

  6. 不定高度实现垂直居中(兼容低版本ie)

    css实现垂直居中的方法比较多,但是每种方法的缺陷也很明显,我尝试对其中一种方法进行了改良 先看原方法: <div class="parent"> <div cl ...

  7. 学习ExtjsForVs(第一个案例HelloWord)

    第一个案例-Hello Word 1.本次练习以ext-4.0.7为例,首先从网上下载ext包. 2.打开包后将里面的三个文件或文件夹拷贝到项目中. resource文件夹 bootstrap.js ...

  8. 认识jeecms开源项目

    1. JEECMS源代码基本结构及相关技术简介: 参考:http://blog.csdn.net/caozhenyu/article/details/47005623

  9. IOS8 设置TableView Separatorinset 分割线从边框顶端开始

    IOS8 设置TableView Separatorinset 分割线从边框顶端开始   在ios8上 [TableViewsetSeparatorInset:UIEdgeInsetsMake(0,0 ...

  10. 论try/catch的重要性,我们经常遇到代码出现无法调试的错误,程序退出的时候崩溃。这跟我们代码日常保护的习惯息息相关。

    每当构造函数或析构函数中出现溢出,会导致调试非常困难,而使用try/catch来处理构造中的初始化就非常重要了. 如上图,在构造函数中,我们的很多初始化动作会放在这里,但是却忽视了,一旦初始化出错了, ...