HAOI2008 木棍分割 数据结构优化dp+二分答案
很久之前打的题,现在补篇博客
打滚动数组
100 |
1712 ms |
1512 KiB |
2019-05-07 17:01:23 |
Short 不打滚动数组
100 |
5219 ms |
100960 KiB |
2019-05-07 15:12:41 |
木棍分割 题解
木棍分割
内存限制:128 MiB时间限制:3000 ms标准输入输出
题目类型:传统评测方式:文本比较
题目描述
有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小.
并将结果mod 10007。。。
输入格式
输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000.
输出格式
输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.
样例
样例输入
3 2
1
1
10
样例输出
10 2
数据范围与提示
两种砍的方法: (1)(1)(10)和(1 1)(10)
二分答案+dp滚动数组
第一步 二分答案求长度
每次枚举木棍可以分成的值下界为所有木棍最小值上界为所有木棍最大值
当 当前值可以分成的时候,比它小的值可能可以分成故让当前r=mid-1
当 当前值不可以分成的时候比它大的值可能分成故让l=mid+1
当r>mid时得到最终答案
然后find函数检验当前值是否可以分成
具体操作:枚举!
初始化add=0,指针=0,块数=0;
只需要扫一遍当add<=x的时候直接在add加上当前这个值;否则令分成的块数++ 并且令add值重新附成当前指针指向的木棍长度
值得注意的一点是 当指针已经指向最后一个数的时候 若add不为0 块数需要+1
最后比较块数与m即可
第二步 dp求方案数
首先暴力枚举求方案数肯定会超时,很自然的想到统计方案需要用dp
首先想要至少开二维 当前切割位置可能由任何满足之间木棍长度之和<=第一步求得的答案 的切割位置转移过来
需要枚举每一根木棍(枚举当前切割的位置) ,每一个前一个切割的位置,和切割的次数
可以看到是n2*m复杂度 还不如打一个暴力 同样是t掉
dp暴力转移式$f[i][j]+=f[k][j-1](if(sum[i]-sum[k-1]<=maxn)$
善良的出题人肯定不会让你AC的
你会得到0分的好成绩
0 |
30150 ms |
然后我们要考虑一些优化
我们可以看到事实上一些位置是加重了的
在每一个切割次数下要枚举一遍k 每次都枚举了k 但事实上每个木棍长是始终不变的
每次枚举一遍就太区区了
我们需要一个数据结构来快速查询每一段所代表的值并且维护一个before数组代表在其之前最长的一段<=第一步求的答案
before可以暴力去求也可以用 lower_bound
for(ll i=1;i<=n;i++)
last[i]=lower_bound(sum+1,sum+i+1,sum[i]-cun)-sum;
理解一下
例如 9 3
5 4 3 2 1 2 3 4 5
这一组数据对应 before为
1 1 1 1 2 2 3 5 7
cun=7;
sum 值 5 9 12 14 15 17 20 24 29
对应下标 1 2 3 4 5 6 7 8 9
last[1]=1 sum[1]-cun=-4
last[2]=1 sum[2]-cun=0
last[3]=1 sum[3]-cun=3
last[4]=1 sum[4]-cun=5
last[5]=2 sum[5]-cun=6
last[6]=2 sum[6]-cun=8
last[7]=3 sum[7]-cun=11
last[8]=5 sum[8]-cun=15
last[9]=7 sum[9]-cun=20
lower_查到的下标 事实就是sum[i]-sum[now]<=cun 其实还是挺好理解的
然后就是数据结构
事实上 考虑到区间查值 我们可以用前缀和(当然树状数组不行 并没有单点修改仅仅是每次要查值而已 前缀和维护是o(1) 树状数组o(logn))
然后dp就完了
代码
#include<bits/stdc++.h>
#define re register
#define i_ inline
#define huan cout<<endl
#define ll int
#define A 50010
ll n,m,before[A],a[A],maxx=-1,last[A],sum[A],su[A],jilu;short f[50101][2];
using namespace std;
#define mod 10007
inline ll read()
{
ll f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return f*x;
}
i_ bool find(ll x)
{
ll zhizhen=0,zan=0,add=0,dangqian;
if(x<maxx)
return false;
while(zhizhen<=n)
{
zhizhen++;
if(add+a[zhizhen]<=x)
{
add+=a[zhizhen];
}
else
{
zan++;
add=a[zhizhen];
dangqian=zhizhen;
}
}
if(add!=0)
zan++;
return (zan<=m?1:0);
}
i_ ll er()
{
ll l=0,r=sum[n],mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if(find(mid)==1)
ans=mid,r=mid-1;
else
l=mid+1;
}
// printf("m=%lld\n",jilu);
return ans;
}
void tiaos(bool x)
{
printf("记录=%lld\n",jilu);
if(x)
{
for(ll i=1;i<=n;i++)
printf("last[%lld]=%lld ",i,last[i]);
cout<<endl;
for(ll i=1;i<=n;i++,puts(""))
for(ll j=0;j<=m;j++)
printf("f[%lld][%lld]=%lld ",i,j,f[i][j]);
return ;
}
else
{
for(ll i=1;i<=n;i++,puts(""))
for(ll j=0;j<=m;j++)
printf("f[%lld][%lld]=%lld ",i,j,f[i][j]);
}
}
int main()
{
// freopen("out.in","r",stdin);
// freopen("wrong.out","w",stdout);
n=read(),m=read();
m+=1;
for(ll i=1;i<=n;i++)
{
a[i]=read();
sum[i]=sum[i-1]+a[i];
maxx=max(a[i],maxx);
} ll cun=er(),zhe=1; m=m-1; ll uscao=0;
for(ll i=1;i<=n;i++)
{
if(sum[i]>cun) break;
else f[i][0]=1;
}
for(ll i=1;i<=n;i++)
last[i]=lower_bound(sum+1,sum+i+1,sum[i]-cun)-sum;
for(ll j=1;j<=m;j++)
{
for(ll i=1;i<=n;i++)
su[i]=su[i-1]+f[i][j&1^1],f[i][j&1]=0;
for(ll i=j+1;i<=n;i++)
f[i][j&1]=(f[i][j&1]+su[i-1]-su[last[i]-1])%mod;
uscao=(uscao+f[n][j&1])%mod;
} // tiaos(1);
cout<<cun<<" "<<uscao;
}
HAOI2008 木棍分割 数据结构优化dp+二分答案的更多相关文章
- BZOJ 1044: [HAOI2008]木棍分割(二分答案 + dp)
第一问可以二分答案,然后贪心来判断. 第二问dp, dp[i][j] = sigma(dp[k][j - 1]) (1 <= k <i, sum[i] - sum[k] <= ans ...
- BZOJ_1044_[HAOI2008]木棍分割_二分答案+DP+单调队列
BZOJ_1044_[HAOI2008]木棍分割_二分答案+DP Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个 ...
- [BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化
1044: [HAOI2008]木棍分割 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 4112 Solved: 1577 [Submit][St ...
- bzoj1044[HAOI2008]木棍分割 单调队列优化dp
1044: [HAOI2008]木棍分割 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4314 Solved: 1664[Submit][Stat ...
- BZOJ1044 [HAOI2008]木棍分割 【二分+Dp】
1044: [HAOI2008]木棍分割 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 4281 Solved: 1644 [Submit][St ...
- BZOJ 1044 木棍分割 解题报告(二分+DP)
来到机房刷了一道水(bian’tai)题.题目思想非常简单易懂(我的做法实际上参考了Evensgn 范学长,在此多谢范学长了) 题目摆上: 1044: [HAOI2008]木棍分割 Time Limi ...
- 1044: [HAOI2008]木棍分割
1044: [HAOI2008]木棍分割 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2161 Solved: 779[Submit][Statu ...
- 【BZOJ1044】[HAOI2008]木棍分割(动态规划,贪心)
[BZOJ1044][HAOI2008]木棍分割(动态规划,贪心) 题面 BZOJ 洛谷 题解 第一问随便二分一下就好了,贪心\(check\)正确性显然. 第二问随便前缀和+单调队列优化一下\(dp ...
- 【BZOJ1044】[HAOI2008]木棍分割
[BZOJ1044][HAOI2008]木棍分割 题面 bzoj 洛谷 题解 第一问显然可以二分出来的. 第二问: 设\(dp[i][j]\)表示前\(i\)个,切了\(j\)组的方案数 发现每次转移 ...
随机推荐
- GitBash管理代码
一.Git是什么? Git是目前世界上最先进的分布式版本控制系统. 1.Git和SVN的区别 SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中 ...
- COM组件对象模型基础
COM组件对象模型 COM组件对象模型是为了创建一种独立于任何编程语言的对象.COM对象提供统一的接口,在不同的编程环境中通过调用COM对象特定接口的方法来完成特定的任务.一般有三种方式编写COM组件 ...
- centos 7.6 安装最新版docker 19.03
systemctl stop docker rpm -qa | grep docker 看到那个删除那个yum erase docker \ docker-client \ docker-client ...
- 什么是NPS 客户净推荐值?
客户忠诚是企业在客户服务方面的最高目标. 客户是否忠诚通过一个问题即可判断,那就是--你会把这家企业推荐给朋友的可能性有多大?这就是著名的NPS指标,本文希望能讲清NPS客户净推荐值是什么,用好客服系 ...
- [bug] C:error: initializer element is not constant
参考 http://codingdict.com/questions/45121
- Ubuntu 配置本地源
Ubuntu 配置本地源 操作系统 Ubuntu 20.04.2 LTS 一.挂载 iso 到本地 mount -t iso9660 -o loop /dev/sr0 /media/cdrom //- ...
- Linux 操作系统(一)命令&用户&权限
以下实例均在Centos7下验证 Centos7 查看命令帮助 man xxx 常用命令 ls / cd - #切到上次目录 cd #回家 cat cat f1 f2 cat f1 f2>f3 ...
- HarmonyOS去除页面顶部title的方式
在config.json文件中module节点中添加如下代码 "metaData":{ "customizeData":[ { "name" ...
- SSTI漏洞-fastapi
0x00 原理 SSTI漏洞全称服务器模板注入漏洞,服务器模板接收了用户输入的恶意代码,未经过滤便在服务端执行并通过渲染模板返回给用户,使得用户可以通过构造恶意代码在服务端执行命令. 0x01 c ...
- 【进阶之路】多线程条件下分段处理List集合的几种方法
这两个月来因为工作和家庭的事情,导致一直都很忙,没有多少时间去汲取养分,也就没有什么产出,最近稍微轻松了一点,后续的[进阶之路]会慢慢回到正轨. 开门见山的说,第一次接触到多线程处理同一个任务,是使用 ...