bzoj1044 [HAOI2008]木棍分割(滚动+后缀和)
来源:互联网 发布:御坂网络 编辑:程序博客网 时间:2024/06/06 08:41
Description
有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连
接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长
度最大的一段长度最小. 并将结果mod 10007。。。
Input
输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,10
00),1<=Li<=1000.
Output
输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.
Sample Input
3 2
1
1
10
Sample Output
10 2
分析:
注意:最多砍断m个连接处
在统计答案的时候,每一个i都要统计答案
第一问:二分判定
(这次的二分终于是一遍过啦)
第二问:
f[i][j],切割了i下,切到了j,
设s为长度的前缀和
f[i][j]=sigma(f[i-1][k]) (s[j]-s[k]<=len)
时间复杂度O(mn^2)
显然需要优化
优化空间
显然f[i]只与f[i-1]有关,滚动数组
优化时间
若s[j]-s[k]<=ans,
那么s[j-1]-s[k]<=ans(其中j-1>k)
这样我们计算s[j]的时候,把符合要求的k的f值都加到一个g数组中
同时g维护一个后缀和(这就需要j从大到小循环)
在计算j-1的时候,若当前k < j-1,就可以直接把g[k]-g[j]加入j-1
否则k=j-1,暴力维护新的k值
还有一种我yy的做法(还没实现)
看一下(s[j]-s[k]<=len)
因为s[i]是单增的,若s[j]-s[k]<=len,那么k+1也符合,这就是一个区间和
设j的临界转移点是p(s[j]-s[p]<=len,p最小)
当转移j+1的时候
j+1的最佳转移点不可能在p点的左侧,
我们就可以维护一个双端队列,暴力维护下一个状态需要加的区间
tip
m++
这里写代码片#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int N=50005;const int mod=10007;const int INF=0x33333333;int v[N],s[N];int n,m,mx=0,mn=INF;int f[3][N],len,p[N];int q[N],tou,wei,g[N];void erfen(){ int l=0,r=s[n],mid; while (l<r) { mid=(l+r)>>1; int tt=1,d=0; for (int i=1;i<=n;i++) { if (v[i]>mid) { tt=INF; break; } if (v[i]+d>mid) tt++,d=v[i]; else d+=v[i]; } if (tt<=m) r=mid; else l=mid+1; } printf("%d ",l); len=l;}void doit() //f[i][j],切割了i下,切到了j{ int i,j,k,ans=0; tou=0,wei=0; for (i=1;i<=n;i++) if (s[i]<=len) f[1][i]=1; //切一下长度符合 else break; int now=0; //滚动数组 for (i=2;i<=m;i++) //切的次数 { memset(f[now],0,sizeof(f[now])); memset(g,0,sizeof(g)); k=n+1; for (j=n;j>1;j--) //s[j]-s[k]<=ans, //那么s[j-1]-s[k]<=ans 显然j要从大到小 { if (j>k) f[now][j]+=(g[k]-g[j])%mod; else k=j; //暴力维护 while (k>1&&s[j]-s[k-1]<=len) { k--; f[now][j]=(f[now][j]+f[now^1][k])%mod; g[k]=(g[k+1]+f[now^1][k])%mod; } } ans+=f[now][n]; //最多砍断m个连接处 now^=1; } printf("%d",ans);}int main(){ scanf("%d%d",&n,&m); m++; //m++ for (int i=1;i<=n;i++) { scanf("%d",&v[i]); s[i]=s[i-1]+v[i]; //前缀和 } erfen(); int tt=n; for (int i=n;i>=1;i--) { while (i>=1&&s[i]-s[tt-1]<=len) tt--; p[i]=tt; } doit(); return 0;}
- bzoj1044 [HAOI2008]木棍分割(滚动+后缀和)
- bzoj1044[HAOI2008]木棍分割
- 【bzoj1044】【HAOI2008】【木棍分割】
- [BZOJ1044] [HAOI2008]木棍分割
- BZOJ1044/HAOI2008木棍分割
- BZOJ1044 [HAOI2008]木棍分割
- bzoj1044: [HAOI2008]木棍分割
- BZOJ1044: [HAOI2008]木棍分割
- 【BZOJ1044】【HAOI2008】木棍分割
- bzoj1044 [HAOI2008]木棍分割
- bzoj1044: [HAOI2008]木棍分割
- [BZOJ1044][HAOI2008]木棍分割(二分+贪心+dp)
- bzoj1044: [HAOI2008]木棍分割(二分+单调队列)
- 【BZOJ1044】【HAOI2008】木棍分割 二分+动规
- [BZOJ1044]HAOI2008木棍分割|DP|二分答案
- 【BZOJ1044】【HAOI2008】木棍分割 动态规划
- BZOJ1044——[HAOI2008]木棍分割
- bzoj1044[HAOI2008]木棍分割 动态规划+二分
- Cannot find class [org.apache.commons.dbcp.BasicDataSource] for bean with name 'dataSource' defined
- PHP合并多个数组
- crond和crontab详解
- wait( )和 waitpid( )
- sessionStorage 学习
- bzoj1044 [HAOI2008]木棍分割(滚动+后缀和)
- 拍黄片运行模式
- bootstrap switch 按钮开关初始化加载赋值,ajax点击切换
- makefile中$< $@ $? $$ 和“四个$”的含义
- Java中的泛型方法
- 自定义可拖拽view
- 最新 Spring 4.2.2 集成 Quartz Scheduler 2.2.2 任务调度示例
- 编写一个登陆框
- JS 结点(属性操作)隐藏与显示(display)