CF的背包DP (备用笔记)
源自vjudge上找到题目,都是背包DP的变式------(推荐点点前两个字🤓)
为什么先做背包而不是线性,因为我善
1.Cut Ribbon CF-189A
完全背包问题:
题意转换,有一个大小为
但是这还不够,题目要求我们每段彩带的长度必须为
然后每个 我有-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背包 罢:
简单理解一下题意:给出一个序列
如何找状态转移?直接选三个数看起来很困难,可以考虑分步 DP ,我们把上面的式子从加号处分开,依次算每一项的解,这样会简单些。
所以有状态表示:
前 个数中 的最大值。 前 个数中 的最大值。 前 个数中 的最大值。
由此推出状态转移方程:
将它们写在一起。
正确性:我们枚举到
最后再注意一下初始化,当
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背包 (哇,真的是你啊,哈哈):
先看题目:(以下求和函数
给出我们长度为 n 的序列 a,b ,选则多个 {
我们将公式转化一下,可得:
这样,我们只要让第
接下来的状态转移和表示就和 01背包 差不多了。
但是看到数据范围会发现数据会有负值,而数组下标不能是复制,所以我们计算一下极值,经计算,发现它的范围在
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];
else
f[i][j]=max(f[i-1][j],f[i-1][j-m[i]]+a[i]);
}
}
}
4.The Great Mixing CF-788C
最伟大的混合 事 DP 罢:
(口瓜,不要把好几种可乐混一起口牙)
给出序列 a,找到若干个
转化一下就是选若干个
唉,🤓👆,还可以优化一下,把每个
我们又发现,开大些,但不能完全开大)
这种背包做法会 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[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 序列,其中有
状态表示:
状态转移:
初始化
计算过程与结果别忘了取模,血与泪的教训
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 棵树,每棵树上有
首先看数据范围,发现体积的范围为
状态表示:
状态转移:
因为存在魔法上限和魔法下限,我们还需要进行特判
当我们枚举
当小恶魔没有走到任何一棵树时,她不会召唤鸟,所以她的魔法为 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");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现