P3092 [USACO13NOV]No Change G 状压 + 二分
P3092 [USACO13NOV]No Change G 状压 + 二分
题意
约翰到商场购物,他的钱包里有()个硬币,面值的范围是。
约翰想按顺序买 个物品(),第i个物品需要花费块钱,()。
在依次进行的购买个物品的过程中,约翰可以随时停下来付款,每次付款只用一个硬币,支付购买的内容是从上一次支付后开始到现在的这些所有物品(前提是该硬币足以支付这些物品的费用)。不幸的是,商场的收银机坏了,如果约翰支付的硬币面值大于所需的费用,他不会得到任何找零。
请计算出在购买完个物品后,约翰最多剩下多少钱。如果无法完成购买,输出
分析
- 注意审题,每次只能投一枚硬币
- 比较小,考虑状压DP,表示状态下的最多能买到第几个物品
- 显然第 枚硬币是从上一个硬币转移而来的,转移方程
- 求可以二分,于是总体复杂度
- 由于要知道多少钱,再开一个辅助数组即可
代码
int n,k;
int dp[1 << 16];
ll f[1 << 16];
ll sum[100005];
int a[100005];
int check(int x,int t){
int l = t;
int r = n;
while(l < r){
int mid = l + r + 1 >> 1;
if(sum[mid] - sum[t - 1] <= x) l = mid;
else r = mid - 1;
}
return l;
}
int main(){
ll res = 1e18;
ll tot = 0;
k = readint();
n = readint();
for(int i = 0;i < k;i++)
a[i] = readint(),tot += a[i];
for(int i = 1;i <= n;i++)
sum[i] = sum[i - 1] + readll();
for(int i = 1;i < (1 << k);i++)
for(int j = 0;j < k;j++)
if(i & (1 << j)) {
int x = i ^ (1 << j);
ll tmp = check(a[j],dp[x] + 1);
if(tmp > dp[i]) {
dp[i] = tmp;
f[i] = f[x] + a[j];
}
if(tmp == n)
res = min(res,f[i]);
}
if(tot - res < 0) puts("-1");
else cout << tot - res;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥