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