2021.12.06 P2511 [HAOI2008]木棍分割(动态规划)

https://www.luogu.com.cn/problem/P2511

题意:

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

分析:

对于第一问,首先二分答案找出ans。

对于第二问,设 sum[i] 表示前 \(i\) 个木棍的长度之和,对于每个木棍 \(i\) ,可以找出在它最前面的木棍 \(j\) ,满足 \(sum_i-sum_j<=ans\) ,把结果存在数组 pos 中。对于前 \(j\) 根木棍分成 \(i\) 组,那么

\[f[i][j]=\sum_{k=pos_j}^{j-1}f[i-1][k]\\
fin=\sum_{i=1}^{m+1}f[i][n]
\]

一看就懂,时间复杂度为傲人的 \(O(n^3)\) ,你可以试试,反正我挂了 。

忽然发现

\[设g[i][j]=\sum_{k=1}^{j}f[i][k]\\
f[i][j]=g[i-1][j]-g[i-1][pos[j]-1]
\]

时间复杂度依旧傲人,不过好了很多,成为 \(O(n^2)\) 。不过你确定不想想空间吗?2个 \(1e7\) 的数组也不小啊。

继续优化:实际上 f 与 g 只和上一轮有关,滚动成一维数组就成~

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; const int N=5e4+10;
const int mod=1e4+7;
int n,m,sum[N],pos[N],a[N],f[N],g[N]; inline int check(int maxn){
int tot=0,len=0;
for(int i=1;i<=n;i++){
if(len+a[i]>maxn)++tot,len=a[i];
else len+=a[i];
if(tot>m)return 0;
}
return tot<=m;
} int main(){
IOS;
cin>>n>>m;
int L=0,R=0,ans;
for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i],L=max(L,a[i]);
R=sum[n];
while(L<R){
int mid=(L+R)>>1;
if(check(mid))ans=mid,R=mid;
else L=mid+1;
}
cout<<ans<<" ";
int lasti=0;
for(int i=1;i<=n;i++)
for(;lasti<i;lasti++)if(sum[i]-sum[lasti]<=ans){
pos[i]=lasti;
break;
}
int fin=sum[n]<=ans;
for(int i=1;i<=n;i++){
if(sum[i]<=ans)f[i]=1;
g[i]=(g[i-1]+f[i])%mod;
}
for(int i=2;i<=m+1;i++){
for(int j=1;j<=n;j++){
f[j]=g[j-1];
if(pos[j]>=1)f[j]=((f[j]-g[pos[j]-1])%mod+mod)%mod;
}
for(int j=1;j<=n;j++)g[j]=(g[j-1]+f[j])%mod;
fin=(fin+f[n])%mod;
}
cout<<fin;
return 0;
}

2021.12.06 P2511 [HAOI2008]木棍分割(动态规划)的更多相关文章

  1. 2021.12.06 P2508 [HAOI2008]圆上的整点(数论+ π )

    2021.12.06 P2508 [HAOI2008]圆上的整点(数论+ \(\pi\) ) https://www.luogu.com.cn/problem/P2508 题意: 求一个给定的圆 \( ...

  2. 2021.12.06 P1450 [HAOI2008]硬币购物(组合数学+抽屉原理+DP)

    2021.12.06 P1450 [HAOI2008]硬币购物(组合数学+抽屉原理+DP) https://www.luogu.com.cn/problem/P1450 题意: 共有 44 种硬币.面 ...

  3. P2511 [HAOI2008]木棍分割

    目录 Description Solution Code Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, ...

  4. [洛谷P2511][HAOI2008]木棍分割

    题目大意:有$n(n\leqslant5\times10^4)$根木棍,连续放在一起,把它们分成$m(\leqslant10^3)$段,要求使得最长的段最短,问最短的长度以及方案数 题解:要使得最长的 ...

  5. Luogu P2511 [HAOI2008]木棍分割 二分+DP

    思路:二分+DP 提交:3次 错因:二分写萎了,$cnt$记录段数但没有初始化成$1$,$m$切的次数没有$+1$ 思路: 先二分答案,不提: 然后有个很$naive$的$DP$: 设$f[i][j] ...

  6. 题解—P2511 [HAOI2008]木棍分割

    这道题第一眼直接一个二分板子把第一问解决掉,然后主要是统计方案. 其实这个方程还不算难推,只要推出来朴素 \(dp\) ,之后的一步一步也很顺理成章,所以这种题主要看能不能静下心来慢慢做. solut ...

  7. luogu P2511 [HAOI2008]木棍分割

    传送门 第一问是一道经典的二分,二分答案\(ans\),然后从前往后扫,判断要分成几段救星了 第二问设\(f_{i,j}\)表示前\(i\)个数分成\(j\)段,每段之和不超过第一问答案的方案,转移就 ...

  8. 2021.12.06 P2501 [HAOI2006]数字序列(动态规划+LIS)

    2021.12.06 P2501 [HAOI2006]数字序列(动态规划+LIS) https://www.luogu.com.cn/problem/P2501 题意: 现在我们有一个长度为 n 的整 ...

  9. 【BZOJ1044】[HAOI2008]木棍分割(动态规划,贪心)

    [BZOJ1044][HAOI2008]木棍分割(动态规划,贪心) 题面 BZOJ 洛谷 题解 第一问随便二分一下就好了,贪心\(check\)正确性显然. 第二问随便前缀和+单调队列优化一下\(dp ...

随机推荐

  1. 5月2日 python学习总结 IO模型

    IO模型 1.阻塞IO 2.非阻塞IO 3.多路复用IO 4.异步IO 一.阻塞IO blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了. 实际上,除非 ...

  2. kernel热补丁

    kernel正在运行的函数,如何实现地址替换的,高并发情况下,如何打热补丁

  3. 如何做一个网站 (C# + MVC Web+ easyUI )

    如何做一个网站 小编想做一个网站,采用技术为:C# + MVC Web+ easyUI 小编经过几天的学习,以及指了几位大神指导,初见效果.建立网站的思路:先列举需要用到了几个知识点,然后逐一攻克,然 ...

  4. BUAA_DS_聊聊链表

    幸福穿着节日的盛装欢迎你. --威廉•莎士比亚<罗密欧与朱丽叶> 1. 说在前面 大家在学数组的时候小脑瓜里有没有这样的疑惑:为什么数组必须是定长的?为什么数组开太长会编译错误?数组越界为 ...

  5. Error和Exception有什么区别?

    Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题:比如内存溢出,不可能指望程序能处理这样的情况:Exception表示需要捕捉或者需要程序进行处理的异常, ...

  6. Docker 的目的是什么?

    Docker 提供了一个可用于托管任何应用程序的容器环境.在此,软件应用程序和 支持它的依赖项紧密打包在一起. 因此,这个打包的产品被称为 Container,因为它是由 Docker 完成的,所以它 ...

  7. 并发包中automic类的原理

    提到同步,我们一般首先想到的是lock,synchronized,但java中有一套更加轻量级的同步方式即atomic类.java的并发原子包里面提供了很多可以进行原子操作的类,比如: AtomicI ...

  8. redis 使用详解

    前戏: 又到了最喜欢的前戏部分,这个前戏可能有点长: Nosql和sql的区别 存储结构与mysql这一种关系型数据库完全不同,nosql存储的是KV形式 应用场景不同,sql支持关系复杂的数据查询, ...

  9. 规范之“用流中的Stream.Of(arr1,arr2)将两个集合合并”

    案例:用流中的Stream.Of(arr1,arr2)将两个集合合并 /** * 功能描述: * 两个对象集合添加到一起 * 在用flatMap扁平化改为Stream<User> * 这样 ...

  10. C++ | 动多态 | 虚函数表

    多态机制 C++语言有三大特性:封装.继承.多态. 其中所谓的多态,即 "同一接口,不同形态".接口在我们 C/C++ 语言中可以理解为函数名,不同形态可以理解为函数执行的功能不同 ...