【BZOJ1044】【tyvj3511】【codevs1870】木棍分割,二分答案+滚动数组+前缀和DP
来源:互联网 发布:怎么连接台湾的网络 编辑:程序博客网 时间:2024/05/18 03:27
传送门1
传送门2
传送门3
写在前面:就我看来,这是一道不错的题
思路:
一.对于“求总长度最大的一段的长度最小值”这个问题,我们比较容易想到二分答案然后判断是否合法,显然这个是可以直接贪心搞的,记录前缀和,从1-n枚举,一旦这一段长度超过mid就砍,并重新计算长度,直到某一单木棍长度超过mid或砍得超过m次,返回非法,否则合法
二.“有多少种砍的方法”这个问题着实让我纠结了很久,最后想出来一个三维DP,记录前i个木棒砍j次并且最后一个砍的地方是k,但显然时间和空间复杂度都是不能承受的,后来知道其实可以去掉k维,DP方程为
就现在看,但这个二维DP的空间复杂度仍是很可怕的,如果我们用short存储(因为答案要mod10007),内存也会达到96M,同时我们要用三个循环控制变量,时间复杂度O(n*n*m),这是必定超时的,那么我们就要对这个DP进行优化
1.首先我们发现对于每一个i来说,k的最小值是固定不变的,即每次我们对f[i][j]加的即是Σ(f[p][j-1])(k<=p<=i-1),那么我们可以在对于每一个j求出一趟后维护一下区间值,争取在较短时间内调出f[i-1][j-1]到f[k][j-1],显然我们可以对每个j求一次f[1][j-1]到f[n][j-1]的前缀和,复杂度为O(n),那么我们就可以顺利在O(n)时间转移所有f[i][j](对于k的求法,我们有一个伪O(n*n)的方法,但实际效果要比n*n快很多),DP的总转移时间就由O(n*n*m)变成了O(n*m)
2.其实题目到这里就可以A了,但空间复杂度很难看,反而还加了一个存前缀和的数组,但我们在存前缀和的时候肯定不是开n*m的数组,同样我们就联想到了对于该题的DP方程我们同样不必开n*m的数组,由于每次转移只用到j-1的状态,所以我们可以改成滚动数组,同样前缀和也是,至此,题目完成
注意:
1.初始化时,我们对所有前缀和小于等于二分出的答案的f[i][0]=1,其他为0
2.转移时f[i][x]一定是赋值而不是+=,因为开的是滚动数组
3.小心越界,一生平安
#include<bits/stdc++.h>#define mod 10007using namespace std;int n,m,minn,ans,x;int f[50010][2],g[50010][2],pos[50010],len[50010],sum[50010];inline bool check(int x){ int k=0,tot=0; for (int i=1;i<=n;i++) if (sum[i]-sum[k]>x) { if (len[i]>x||tot==m) return 0; tot++; k=i-1; } return 1;}main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&len[i]), sum[i]=sum[i-1]+len[i]; int l=1,r=sum[n],mid=(l+r)>>1; while (l<=r) { if (check(mid)) minn=mid,r=mid-1; else l=mid+1; mid=(l+r)>>1; } for (int i=1;i<=n;i++) if (sum[i]<=minn) f[i][0]=1; else break; for (int i=1;i<=n;i++) { if (sum[i]<=minn) continue; for (int j=i-1;j>=0;j--) if (sum[i]-sum[j]>minn) {pos[i]=j+1;break;} } while (m--) { for (int i=1;i<=n;i++) g[i][x]=g[i-1][x]+f[i][x]; x^=1; for (int i=1;i<=n;i++) f[i][x]=(g[i-1][!x]-g[max(pos[i]-1,0)][!x])%mod; ans=(ans+f[n][x])%mod; } printf("%d %d",minn,ans);}
- 【BZOJ1044】【tyvj3511】【codevs1870】木棍分割,二分答案+滚动数组+前缀和DP
- [BZOJ1044]HAOI2008木棍分割|DP|二分答案
- NKOJ 4244 (HAOI 2008) 木棍分割 (二分答案+DP+单调队列+前缀和优化+滚动数组)
- HAOI2008 木棍分割 二分答案 前缀和优化 单调队列 滚动数组
- 1044: [HAOI2008]木棍分割 二分答案+DP+前缀和优化
- bzoj1044 木棍分割 二分+贪心&dp优化
- BZOJ1044 [HAOI2008]木棍分割 【二分+Dp】
- BZOJ1044 [HAOI2008]木棍分割(二分答案/单调性优化dp+递推优化)
- BZOJ 1044: [HAOI2008]木棍分割 DP,前缀和优化,二分答案
- [BZOJ1044][HAOI2008]木棍分割(二分+贪心+dp)
- bzoj1044 [HAOI2008]木棍分割(滚动+后缀和)
- 【BZOJ1044】【HAOI2008】木棍分割 二分+动规
- bzoj1044[HAOI2008]木棍分割 动态规划+二分
- bzoj1044[HAOI2008]木棍分割
- 【bzoj1044】【HAOI2008】【木棍分割】
- [BZOJ1044] [HAOI2008]木棍分割
- BZOJ1044/HAOI2008木棍分割
- BZOJ1044 [HAOI2008]木棍分割
- HDU2519新生晚会(组合数公式)
- 蓝桥杯--2012--奇怪的比赛(全排列)
- Android新手入门2016(3)--Android真机调试
- Codeforces 631E:Product Sum
- C# 使用keybd_event()函数模拟键盘按键
- 【BZOJ1044】【tyvj3511】【codevs1870】木棍分割,二分答案+滚动数组+前缀和DP
- 【译】UNIVERSAL IMAGE LOADER.PART 2---ImageLoaderConfiguration详解
- kmeans++算法流程
- Codeforces #345 div1 D. Zip-line LIS dp
- Equipment uva1508
- 从两个有序数组的并集中寻找第k小元素
- bzoj 1085 骑士精神
- 删除算法 2-remove_copy()
- MRC到ARC的自动转换