看 DP 的时候翻到的题,发现这题的坑鸽子了一年半

这个状态感觉比较厉害,还是来记录一下吧。

首先硬币数量很少让我们想到状压,可以想出来一个十分 navie 的状态:\(dp[S][n]\) 表示用过 \(S\) 这些硬币,走到 \(n\) 的最少花费。

转移也是十分暴力,但是不可能通过此题。

不可能继续考虑状态数量过高的做法,所以考虑 \(O(n)\) 的状态或者 \(O(2^k)\) 甚至 \(O(k2^k)\) 的状态。

我也不知道这个状态是怎么想出来的。。。觉得非常厉害(或者说我太菜了)

设 \(f[S]\) 为使用了这些金币能走的最远的位置。于是可以枚举一个子集进行转移,加一个二分就能够做到 \(O(2^k\log n)\)。

#include<cstdio>
typedef long long ll;
const int M=1<<16;
int n,k,m[20],dp[M],sum[100005];
ll ans=1e18,num,f[M];
inline ll min(const ll&a,const ll&b){
return a>b?b:a;
}
inline int BS(int id,int M){
int L=id,R=n,mid,ans=id;
while(L<=R)if(sum[mid=L+R>>1]-sum[id-1]<=M)ans=mid,L=mid+1;else R=mid-1;
return ans;
}
signed main(){
int i,j,x,id;
scanf("%d%d",&k,&n);
for(i=0;i^k;++i)scanf("%d",m+i),num+=m[i];
for(i=1;i<=n;++i)scanf("%d",sum+i),sum[i]+=sum[i-1];
for(i=0;i^1<<k;++i){
for(j=0;j^k;++j)if(i>>j&1){
x=i^1<<j;
if((id=BS(dp[x]+1,m[j]))>dp[i]){
dp[i]=id;f[i]=f[x]+m[j];
if(dp[i]==n&&f[i]<ans)ans=f[i];
}
}
}
printf("%lld",ans==1e18?-1:num-ans);
}

最新文章

  1. Sudoku 数独游戏
  2. 模仿console自写函数打印js的对象
  3. Nginx限速遇到的问题
  4. 2013xlsm格式文件处理
  5. C#根据身份证号码,计算生日、年龄、性别
  6. 分析Masonry
  7. 巧解Tomcat中JVM内存溢出问题
  8. POJ Code the Tree 树的pufer编号
  9. python基础学习笔记6--异常
  10. spring mvc:@RequestParam与@ModelAttribute异同
  11. JAVA应用程序转换为Applet
  12. C#中添加log4net(日志文件)
  13. Vue学习Day002
  14. [Hive_4] Hive 插入数据
  15. 钉钉消息通知机器人python版
  16. web@css样式进阶--图形字体、动画、显隐....
  17. Python常用内置函数介绍
  18. 深圳scala-meetup-20180902(3)- Using heterogeneous Monads in for-comprehension with Monad Transformer
  19. POM、STS、IOC、DI、AOP
  20. python脚本参数传递

热门文章

  1. NSArray 与字符串
  2. Java内存分析简单介绍
  3. 还在做廉价的劳动力?部署PXE实现Kickstart无人值守安装
  4. pandas中常用的操作一
  5. PHP和MySQL爱考的10道题
  6. 「微前端实践」使用Vue+qiankun微前端方案重构老项目的本地验证
  7. java Excel 简单工具
  8. Eclipse插件开发demo
  9. #刷题记录--剑指 Offer 07. 重建二叉树
  10. 软考高级及杭州E类人才申请经验分享