二分/DP


  真是一道好题!

  第一问很简单的二分……

  第二问一开始我想成贪心了,其实应该是DP的= =

  然后没有注意……又MLE又TLE的……这题要对DP进行时空两方面的优化!!

  题解:(by JoeFan)

使用前缀和,令 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) 。满足时间限制。

 /**************************************************************
Problem: 1044
User: Tunix
Language: C++
Result: Accepted
Time:4152 ms
Memory:4396 kb
****************************************************************/ //BZOJ 1044
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int N=1e5+,INF=~0u>>,P=;
typedef long long LL;
/******************tamplate*********************/
int n,m,ans,a[N],f[N][],pos[N],sumf[N][];
LL s[N];
bool check(int len){
int cnt=,sum=;
F(i,,n){
if (a[i]>len) return ;
if (sum+a[i]>len){
cnt++; sum=a[i];
}else sum+=a[i];
}
return cnt<=m;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1044.in","r",stdin);
freopen("1044.out","w",stdout);
#endif
n=getint(); m=getint();
F(i,,n) {a[i]=getint();s[i]=s[i-]+a[i];} int l=,r=s[n],mid;
while(l<=r){
mid=l+r>>;
if (check(mid)) ans=mid,r=mid-;
else l=mid+;
}
printf("%d ",ans);
F(i,,n) sumf[i][]=;
int way=;
F(j,,m+){
int now=j&;
sumf[][now]=;
F(i,,n){
if (!pos[i])
pos[i]=pos[i-]; while(s[i]-s[pos[i]]>ans) pos[i]++;
f[i][now]=(sumf[i-][now^]-sumf[pos[i]-][now^]+P)%P;
sumf[i][now]=(sumf[i-][now]+f[i][now])%P;
}
way=(way+f[n][now])%P;
}
printf("%d\n",way);
return ;
}

1044: [HAOI2008]木棍分割

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2008  Solved: 725
[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

[Submit][Status][Discuss]

【BZOJ】【1044】【HAOI2008】木棍分割的更多相关文章

  1. BZOJ 1044: [HAOI2008]木棍分割(二分答案 + dp)

    第一问可以二分答案,然后贪心来判断. 第二问dp, dp[i][j] = sigma(dp[k][j - 1]) (1 <= k <i, sum[i] - sum[k] <= ans ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. 1044: [HAOI2008]木棍分割

    1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2161  Solved: 779[Submit][Statu ...

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

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

  10. 【BZOJ】1044: [HAOI2008]木棍分割(二分+dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1044 如果只求最大的最小,,直接二分就行了...可是要求方案.. 好神! 我竟然想不到! 因为我们得 ...

随机推荐

  1. Vue.js学习 Item5 -- 计算属性computed与$watch

    在模板中绑定表达式是非常便利的,但是它们实际上只用于简单的操作.模板是为了描述视图的结构.在模板中放入太多的逻辑会让模板过重且难以维护.这就是为什么 Vue.js 将绑定表达式限制为一个表达式.如果需 ...

  2. Ajax异步刷新局部页面的小李子

    看到下面那幅图没有,我们要的是当点击确定以后,根据条形码搜索出商品信息,并且异步刷新右边页面:

  3. PHP常用函数和常见疑难问题解答

    PHP常用库函数介绍 一.PHP字符串操作常用函数 1.确定字符串长度  int strlen(string str) 2.比较两个字符串 a. strcmp函数对两个字符串进行二进制安全的比较,并区 ...

  4. mysql 修改字段长度

    mysql 修改字段长度 alter table news  modify column title varchar(130); alter table 表名 modify column 字段名 类型 ...

  5. 随机获取Mysql数据表的一条或多条记录

    随机获得Mysql数据表的一条或多条记录有很多方法,下面我就以users(userId,userName,password......)表(有一百多万条记录)为例,对比讲解下几个方法效率问题: sel ...

  6. jquery.tmpl 用法(附上详细案例)

    js的模板引擎就和服务端的差不多,都是更好更快的拼接html用于显示,我参考了文章:http://www.cnblogs.com/zhuzhiyuan/p/3510175.html tmpl常用标签 ...

  7. linux 命令 more

    more命令: 从前往后读取文件,启动时加载整个文件,让整个文件的内容从上到下显示在屏幕上. 可以逐页读取,空格(space):下一页,b键(back):上一页,而且还有搜索字符串的功能. more ...

  8. OpenStack:安装Horizon

    1. 安装:# apt-get install memcached libapache2-mod-wsgi openstack-dashboard!Note for Ubuntu users# apt ...

  9. OpenStack:安装Keystone

    >安装Keystone1. 安装# apt-get install keystone2. 创建dbcreate database keystone;grant all privileges on ...

  10. C# socket 实现消息中心向消息平台 转发消息 (修改)

    using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using ...