CF的背包DP (备用笔记)

news/2024/11/13 8:24:32/文章来源:https://www.cnblogs.com/mega-chimera/p/18530539

源自vjudge上找到题目,都是背包DP的变式------(推荐点点前两个字🤓)
为什么先做背包而不是线性,因为我善

1.Cut Ribbon CF-189A

完全背包问题:
题意转换,有一个大小为 \(n\) 的背包,有三个物品,体积为 a,b,c,最多能装多少个物品。

但是这还不够,题目要求我们每段彩带的长度必须为 \(a,b,c\) 其中之一,换而言之,我们必须装满背包。

然后每个 \(f\) 赋初值唯一,特别的 \(f_0\) 初值为 0 ,因为长度为零的彩带只能分为 0 段,如果是 -1 的话是不是不太符合实际(我有-1条彩带?),再跑完全背包板子时要注意特判,如果 \(f_{i,j}\) 为 -1 就略过。

code

memset(f,-1,sizeof(f));
f[0]=0;
for(int i=1;i<=3;i++){for(int j=v[i];j<=n;j++){if(f[j-v[i]]<0) continue;f[j]=max(f[j],f[j-v[i]]+1);}
}

2.Marvolo Gaunt's Ring CF-855B

应该事 01背包 罢:

简单理解一下题意:给出一个序列 \(a\) ,要求我们取出三个数 \(a_i,a_j,a_k\) \((1\le i\le j\le k\le n)\)\(p*a_i+q*a_j+r*a_k\) 的最大值,并且会存在负数。

如何找状态转移?直接选三个数看起来很困难,可以考虑分步 DP ,我们把上面的式子从加号处分开,依次算每一项的解,这样会简单些。

所以有状态表示:\(f_{i,1/2/3}\)

  • \(f_{i,1}\)\(i\) 个数中 \(p*a_i\) 的最大值。
  • \(f_{i,2}\)\(i\) 个数中 \(p*a_i+q*a_j\) 的最大值。
  • \(f_{i,3}\)\(i\) 个数中 \(p*a_i+q*a_j+r*a_k\) 的最大值。

由此推出状态转移方程:

  • \(f_{i,1}=max(f_{i-1,1},p*a_i)\)
  • \(f_{i,2}=max(f_{i-1,2},f_{i,1}+q*a_i)\)
  • \(f_{i,3}=max(f_{i-1,3},f_{i,2}+r*a_i)\)

将它们写在一起。

正确性:我们枚举到 \(a_x\) 时,有两种情况:选或不选。如果不选,对结果没有影响,如果选,则必定满足 \(f\) 的定义。

最后再注意一下初始化,当 \(f_{i,1}=f_{i,2}=f_{i,3}=-8e18\) 有负数存在,初始化的数尽量小些。别忘了开 long long,小心见祖宗
code:

f[0][1]=f[0][2]=f[0][3]=-8e18;
for(int i=1;i<=n;i++){f[i][1]=max(f[i][1],p*a[i]);f[i][2]=max(f[i-1][2],f[i][1]+q*a[i]);f[i][3]=max(f[i-1][3],f[i][2]+r*a[i]);
}

3.Dima and Salad CF-366C

也事 01背包 (哇,真的是你啊,哈哈):

先看题目:(以下求和函数\(\sum_{i=1}^{m}\) 简写成 \(\sum\) 因为我懒)
给出我们长度为 n 的序列 a,b ,选则多个 {\(a_i\)\(b_i\)} 使得 \(\frac { \sum a_i }{ \sum b_i}=k\) ,并且 \(\sum a_i\) 的值最大。

我们将公式转化一下,可得:\(\sum(a_i-b_i*k)=0\)
这样,我们只要让第 \(i\) 个水果的价值为 \(a_i-b_i*k\) ,最后只要让价值总和为 0 就可以了。

接下来的状态转移和表示就和 01背包 差不多了。
但是看到数据范围会发现数据会有负值,而数组下标不能是复制,所以我们计算一下极值,经计算,发现它的范围在 \([-10^5,10^4]\) ,所以只需要每个数加上 \(10^5\) 就可以了。

code:

for(int i=1;i<=n;i++){for(int j=110000;j>=0;j--){if(j-m[i]<=110000 && j-m[i]>=0){ if(f[i-1][j-m[i]]==-1)f[i][j]=f[i-1][j];elsef[i][j]=max(f[i-1][j],f[i-1][j-m[i]]+a[i]);}}
}

4.The Great Mixing CF-788C

最伟大的混合 事 DP 罢:

口瓜,不要把好几种可乐混一起口牙

给出序列 a,找到若干个 \(\frac{a_i}{1000}\) ,使它们的和为 \(\frac{n}{1000}\)。并且我们可以重复选取同一个 \(a_i\)

转化一下就是选若干个 \(a_i\) ,使他们的平均数为 n。
唉,🤓👆,还可以优化一下,把每个 \(a_i\) 减去 n,这样只要让他们的和为 0 就可以了。

我们又发现,\(k\le 10^6\) 不太好DP,唉,🤓👆我们发现除数是 1000,也就意味着本质不同的数一共就 1000 个(去重),上下界大概开 1e6就可以了(开大些,但不能完全开大

这种背包做法会 TLE 即使 CF 的神机有 1s 1e9的运算量

code

for(int i=1;i<=m;i++){f[N+a[i]]=1;if(a[i]<0){ for(int j=sum;j>=-sum;j--){f[j+N]=min(f[j+N],f[j+N-a[i]]+1);}}else{for(int j=-sum;j<=sum;j++){f[j+N]=min(f[j+N],f[j+N-a[i]]+1);}}
}

正解( T 不了了😋):

可以用 BFS ,将已有浓度的可乐的权值的设为 \(w_i=1\),其它为inf,然后把它们放进队列。每次取队头元素,把它加上所有可能的饮料的情况都枚举一遍。若有新扩展的点,加入队列。

最后结果如果 w[1000] 没有被更新,则可以无法混合出来,否则可以混合出来。(因为我们存数组时加了 1000 ,所以此时的 w[1000] 是 w'[0])

code

//BFS过程,如何可以最好设 P=1000,Q=2000 万一少个或多个零就寄了。
for(int i=0;i<=2000;i++){if(w[i]==1) q.push(i);
}while(!q.empty()){int u=q.front();q.pop();for(int i=0;i<=2000;i++){if(w[i]==1 && w[u+i-1000]==inf){q.push(u+i-1000);w[u+i-1000]=w[u]+1;}}
}

5.Caesar's Legions CF-118D

也事 背包DP(废话):

给出一个 01 序列,其中有 \(n_1\) 个 0 和 \(n_2\) 个 1,而且连续的 0 的个数不超过 \(k_1\) ,连续的 1 的个数不超过 \(k_2\) 个,这样的序列为合法序列。求合法序列方案数并且对 \(10^8\) 取模。

状态表示:\(f_{i,j,k,0/1}\) 表示已经使用了 \(i\) 个 1, \(j\) 个 0,并且有 \(k\) 个连续的 0/1,的方案数;(虽然是四维的但是好理解)

状态转移:

\((i>0,k\in[2,k_1])\) \(f_{i,j,k,0}=f_{i-1,j,k-1,0}\)
\((i>0,k\in[1,k_2])\) \(f_{i,j,1,0}+=f_{i-1,j,k,0}\)
\((j>0,k\in[2,k_2])\) \(f_{i,j,k,1}=f_{i,j-1,k-1,1}\)
\((j>0,k\in[1,k_1])\) \(f_{i,j,1,1}+=f_{i,j-1,k,1}\)

初始化 \(f_{1,0,1,0}=f_{0,1,1,1}=1\) 只使用 1 个 0/1 的方案数必定是 1。
计算过程与结果别忘了取模,血与泪的教训

code

f[1][0][1][0]=f[0][1][1][1]=1;
for(int i=0;i<=n1;i++){for(int j=0;j<=n2;j++){if(i>0){for(int k=2;k<=k1;k++){f[i][j][k][0]=f[i-1][j][k-1][0];}for(int k=1;k<=k2;k++){f[i][j][1][0]=(f[i][j][1][0]+f[i-1][j][k][0])%mod;}}if(j>0){for(int k=2;k<=k2;k++){f[i][j][k][1]=f[i][j-1][k-1][1];}for(int k=1;k<=k1;k++){f[i][j][1][1]=(f[i][j][k][1]+f[i][j-1][k][1])%mod;}}}
}

6.Birds CF-922E

啊?小恶魔? 嗯,背包:

有 n 棵树,每棵树上有 \(c_i\) 只鸟,可以消耗 \(cost_i\) 的魔法召唤一只鸟,并增加魔法上限 \(B\) , 她可以从 \(0~c_i\) 中召唤任意个数的鸟,她的初始魔法上限是 \(W\),当她从第 \(i\) 棵树走到第 \(i+1\) 棵树,并恢复 \(X\) 点魔法,并且不能超上限,求召唤的最多的鸟的数目。

首先看数据范围,发现体积的范围为 \([0~10^9]\) 所以不能用往常的方式做状态表示,既然魔法值和上线无法用来维护 DP,那么我们可以考虑其他的值,再观察数据范围,我们发现,\(\sum_{i=1}^{n} c_i\le 10^4\) 这提醒我们可以用鸟的数目来做状态表示。

状态表示:\(f_{i,j}\) 小恶魔走到第 \(i\) 棵树,召唤了 \(j\) 只鸟的魔法上限

状态转移:\(f_{i,j}=max\{ f_{i-1,j-k}+X-cost_i*k \}\)
因为存在魔法上限和魔法下限,我们还需要进行特判 \(0<f_{i,j}<W+B*j\)

当我们枚举 \(j\) 时要使用前缀和,因为随着走过的树的数目增加,\(j\) 的最大值是递增的,当枚举 \(k\) 时,我们要对枚举的 \(j\)\(c_i\) 取最小值,因为在第 \(i\) 棵树上最多会有 \(c_i\) 只鸟。
当小恶魔没有走到任何一棵树时,她不会召唤鸟,所以她的魔法为 W,即 \(f_{0,0}=W\)
最后倒序枚举,求出召唤出的鸟的最大数目就可以了。

code:

memset(f,-1,sizeof(f));
f[0][0]=W;
for(int i=1;i<=n;i++){for(int j=0;j<=s[i];j++){int m=min(c[i],j);for(int k=0;k<=m;k++){if(f[i-1][j-k]-v[i]*k>=0 && f[i-1][j-k]!=-1){f[i][j]=max(f[i][j],f[i-1][j-k]+X-v[i]*k);					}}if(f[i][j]>W+B*j) f[i][j]=W+B*j;}
}
for(int i=s[n];i>=1;i--){if(f[n][i]!=-1){printf("%lld\n",i);return 0;}
}
puts("0");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/831598.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024/11/11

软件设计 实验12:外观模式 在计算机主机(Mainframe)中,只需要按下主机的开机按钮(on()),即可调用其他硬件设备和软件的启动方法 ,如内存(Memory)的自检(check())、CPU的运行(run())、硬盘(HardDisk)的读取(read())、操作系统(OS)的载入(load()),如果某一过程发生错误则计算…

2024.11.6(周三)

用透明组合模式实现教材中的“文件夹浏览”这个例子。 实验要求: 1.文件的执行不需真正实现,只需简单提示即可; 2.提交源代码; 3.注意编程规范。1、类图2、源代码 #include <iostream> #include <string> #include<list> using namespace std;class Abst…

2024.11.7(周四)

用装饰模式模拟手机功能的升级过程:简单的手机(SimplePhone)在接收来电时,会发出声音提醒主人;而JarPhone除了声音还能振动;更高级的手机(ComplexPhone)除了声音、振动外,还有灯光闪烁提示。 实验要求: 1.提交类图; 2.提交源代码; 3.注意编程规范。1、类图2、源代码 #i…

2024.11.5(周二)

用桥接模式实现在路上开车这个问题,其中,车可以是car或bus,路可以是水泥路或沥青路。 实验要求: 1.画出对应的类图; 2.提交源代码; 3.注意编程规范。1、类图2、源代码 (1) Bus.java package test;public class Bus implements Vehicle{@Overridepublic void run() {Sy…

CFAT:三角窗口实现图像超分辨率

CFAT:三角窗口实现图像超分辨率基于变换器的模型通过利用其固有的捕获复杂上下文特征的能力,彻底改变了图像超分辨率(SR)的效果。如今,在Transformer架构中使用的重叠矩形移位窗口技术是超分辨率模型中的一种常见做法,可以提高图像放大的质量和鲁棒性。然而,它在边界处存…

CFAT:释放三角窗口实现图像超分辨率

CFAT:释放三角窗口实现图像超分辨率基于变换器的模型通过利用其固有的捕获复杂上下文特征的能力,彻底改变了图像超分辨率(SR)的效果。如今,在Transformer架构中使用的重叠矩形移位窗口技术是超分辨率模型中的一种常见做法,可以提高图像放大的质量和鲁棒性。然而,它在边界…

读数据工程之道:设计和构建健壮的数据系统34读后总结与感想兼导读

读后总结与感想兼导读1. 基本信息 数据工程之道:设计和构建健壮的数据系统[美]乔里斯(Joe Reis),[美]马特豪斯利(Matt Housley)著机械工业出版社,2024年2月出版1.1. 读薄率 书籍总字数473千字,笔记总字数109584字。 读薄率109584473000≈23.17% 1.2. 读厚方向Data Mesh权威指…

鸿蒙NEXT开发案例:抛硬币

【1】引言(完整代码在最后面) 本项目旨在实现一个简单的“抛硬币”功能,用户可以通过点击屏幕上的地鼠图标来模拟抛硬币的过程。应用会记录并显示硬币正面(地鼠面)和反面(数字100面)出现的次数。为了增强用户体验,我们还添加了动画效果,使抛硬币的过程更加生动有趣。 …

【CodeForces训练记录】Codeforces Round 986 (Div. 2)

训练情况赛后反思 C题逆风翻盘,可能勉强青名了。A题愣神了,我觉得还能再做的快一点。 A题 给定一个字符串,NWSE,重复着字符串走,我们直接模拟即可,用 while 来判断是否走到终点,然后对于不可能走到的终点,我选择了一个不会超时的步数范围,超出就跳出 while 即可,最后…

24. 使用MySQL之使用游标

1. 游标 由前几章可知,MySQL检索操作返回一组称为结果集的行。这组返回的行都是与SQL语句相匹配的行(零行或多行)。 使用简单的SELECT语句,例如,没有办法得到第一行、下一行或前10行,也不存在每次一行地处理所有行的简单方法(相对于成批地处理它们)。 有时,需要在检索…

Python clickhouse-driver 类库使用学习总结

实践环境 python3 .9.13 clickhouse-driver 0.2.9 实践操作 # -*- coding:utf-8 -*-import clickhouse_driverif __name__ == __main__:host = 192.168.88.131port = 9000 # 注意,不能使用默认的8123username = testaccpassword = test1234database = default# 连接方式1# con…

随波逐流工具使用_Week1

跟着大师傅的公众号做题的week1 来源以及说明 (文章主要是了解怎样使用长弓三皮大师傅的随波逐流工具,wp以及附件来自大师傅长弓三皮) (这周主要是做笔记的软件老是出现问题,有一些笔记有点乱,后面慢慢改进) 软件及题目下载 http://www.1o1o.xyz/bo_softdown.html CTF题目wr…