ACW 各种背包模型题 day36

恭喜江莉ec final 夺冠

所以昨天高强度看榜 没有写题

dbq QAQ

AcWing 1022. 宠物小精灵之收服

二维费用背包

空间不够我们可以滚动数组优化 不过要反着跑

然后就是体力 j 不能为0 我可以将他看成一个j-1的背包就是了 

反正不可以判断时加j>k这样会忽略从0开始的转化

最后自然check时 0 ~ v2-1 

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
const int M = 5e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int V1,V2,f[N][N],n;
signed main(){
    fast
    cin>>V1>>V2>>n;
    for(int i=1;i<=n;i++){
        int v1,v2;cin>>v1>>v2;
        for(int j=V1;j>=v1;j--)
            for(int k=V2-1;k>=v2;k--)
                f[j][k]=max(f[j][k],f[j-v1][k-v2]+1);
    }
    cout<<f[V1][V2-1]<<' ';
    int j;
    for(j=0;j<=V2-1;j++)if(f[V1][V2-1]==f[V1][j])break;
    cout<<V2-j<<endl;
    return ~~(0^_^0);
}

AcWing 278. 数字组合  

呃呃 把f[i-1][j]和f[i-1][j-vi]弄一起了 卡了一会

实际上肯定时不行的 

越学越回去了 属于是

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N][M],n,m,a[N];
signed main(){
    fast
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=0;i<=n;i++)f[i][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {f[i][j]=f[i-1][j];if(j>=a[i])f[i][j]+=f[i-1][j-a[i]];}
    cout<<f[n][m]<<endl;
    return ~~(0^_^0);
}

AcWing 1023. 买书

注意j枚举从0开始就是了 因为0的时候我们初始化没到 而把初始化提外面写是能写

要多几行

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[5][N],n,a[5]={0,10,20,50,100};
signed main(){
    fast
    cin>>n;
    f[0][0]=1;
    for(int i=1;i<=4;i++)
        for(int j=0;j<=n;j++)
            for(int k=0;k*a[i]<=j;k++)
                f[i][j]+=f[i-1][j-k*a[i]];
    cout<<f[4][n]<<endl;
    return ~~(0^_^0);
}

AcWing 1021. 货币系统

#include <bits/stdc++.h>
using namespace std;
const int N = 3e3+10;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int n,m,f[20][N];
signed main(){
    fast
    cin>>n>>m;
    int a[20];
    for(int i=1;i<=n;i++)cin>>a[i];
    f[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k*a[i]<=j;k++)
                f[i][j]+=f[i-1][j-k*a[i]];
    cout<<f[n][m]<<endl;
    return ~~(0^_^0);
}

AcWing 532. 货币系统

我们不难看出这个题意是让大的数被小的数表示

最开始想的是填表法 多了一维 T了

后来想好像可以刷表 然后 就过了

我们把最开始存的表示成2 能换算过去变成1 

我们只要碰到大于0的就刷一遍

不过只能刷比他小的面值把

这道题就结束咯~~~

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}

signed main(){
    fast
    int t;cin>>t;
    while(t--){
        int f[25010]={0};
        int a[N],n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i],f[a[i]]=2;
        sort(a+1,a+n+1);
        int cnt=1;
        for(int i=a[1];i<=a[n];i++){
            if(f[i]>0){
                for(int j=1;j<=cnt;j++){
                    if(a[j]+i<=a[n])f[a[j]+i]=1;
                }
            }
            if(i==a[cnt])cnt++;
        }
        int ans=0;
        for(int i=1;i<=n;i++)if(f[a[i]]==2)ans++;
        cout<<ans<<endl;
    }
    return ~~(0^_^0);
}

AcWing 6. 多重背包问题 III

我超

好几把难

暴力我们都会

我看了这道题 他tag说要单调队列 可是我想了半天也没想出来那里可以单调队列

因为我们枚举每个K的时候就是O(1)的 

然后退到j层 是根本和上一层无关的

呃呃

他居然是有个性质 我们%v后是小于v的 然后利用小的 递推过去

并且我们直接还有个(我们就用滚动数组来说啊

f[j]=max(f[j],f[j-v]+w,f[j-2v]+2w...,f[j-sv]+sw)

f[j-v]=max(   f[j-v],     f[j-2v]+w,....f[j-sv]+(s-1)w,f[j-(s+1)v]+sw)

f[j-2v]=...

f[j-3v]=...

这里也就是我们为什么不能用完全背包的来优化 因为完全背包是固定了s项 没有s+1项的

然后我们发现我们每个j-kv都是求前s个的max

这不就单调队列吗!

经过单调队列优化我们的时间复杂度O(nm)(因为可以把里面两层优化成线性

然后就是很重要的一点我们每次f[j-kv]后面加的w都是不同的

我们设余数为r

f[r]=max(f[r])

f[r+v]=max(f[r+v],f[r+v-v]+w)

f[r+2v]=max(f[r+2v],f[r+2v-v]+w,f[r+2v-2v]+2w)

我们把里面都减去合适kw

f[r]=max(f[r])

f[r+v]=max(f[r+v]-w,f[r])+w

f[r+2v]=max(f[r+2v]-2w,f[r+v]-w,f[r])+2w

当然我们入队比较的时候随便比比只要相对不变就是了

但是入队时应该严格的绝对值入队那就是当前的(k-dq.front)/v*w

当然你可以把这个max(f[r+2v]-2w,f[r+v]-w,f[r])拿去入队 当然出来的时候就要加上kw

#include <bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N],backup[N];
signed main(){
    fast
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++){
        int v,w,s;cin>>v>>w>>s;
        memcpy(backup,f,sizeof f);
        for(int j=0;j<v;j++){
            int dq[N];
            int tt=-1,hh=0;
            for(int k=j;k<=m;k+=v){
                while(hh<=tt&&dq[hh]<k-s*v)hh++;
                while(hh<=tt&&backup[dq[tt]]-(dq[tt]-j)/v*w<=backup[k]-(k-j)/v*w)tt--;
                dq[++tt]=k;
                if(hh<=tt)f[k]=max(f[k],backup[dq[hh]]+(k-dq[hh])/v*w);
            }
        }
    }
    cout<<f[m]<<endl;
    return ~~(0^_^0);
}

AcWing 1019. 庆功会

一模一样 我甚至数据范围都没改

#include <bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N],backup[N];
signed main(){
    fast
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++){
        int v,w,s;cin>>v>>w>>s;
        memcpy(backup,f,sizeof f);
        for(int j=0;j<v;j++){
            int dq[N];
            int tt=-1,hh=0;
            for(int k=j;k<=m;k+=v){
                while(hh<=tt&&dq[hh]<k-s*v)hh++;
                while(hh<=tt&&backup[dq[tt]]-(dq[tt]-j)/v*w<=backup[k]-(k-j)/v*w)tt--;
                dq[++tt]=k;
                if(hh<=tt)f[k]=max(f[k],backup[dq[hh]]+(k-dq[hh])/v*w);
            }
        }
    }
    cout<<f[m]<<endl;
    return ~~(0^_^0);
}

 ACWing 7. 混合背包问题

处理一下输入就是了

#include <bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N],backup[N];
signed main(){
    fast
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++){
        int v,w,s;cin>>v>>w>>s;
        if(s==0)s=2e9;
        else if(s==-1)s=1;
        memcpy(backup,f,sizeof f);
        for(int j=0;j<v;j++){
            int dq[N];
            int tt=-1,hh=0;
            for(int k=j;k<=m;k+=v){
                while(hh<=tt&&dq[hh]<k-s*v)hh++;
                while(hh<=tt&&backup[dq[tt]]-(dq[tt]-j)/v*w<=backup[k]-(k-j)/v*w)tt--;
                dq[++tt]=k;
                if(hh<=tt)f[k]=max(f[k],backup[dq[hh]]+(k-dq[hh])/v*w);
            }
        }
    }
    cout<<f[m]<<endl;
    return ~~(0^_^0);
}

AcWing 8. 二维费用的背包问题

看错题了 这也能难度中等???

我说再加一维k都称不上把呃呃

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N][N],n,V1,V2;
signed main(){
    fast
    cin>>n>>V1>>V2;
    for(int i=1;i<=n;i++){
        int w,v1,v2;cin>>v1>>v2>>w;
        for(int i=V1;i>=1;i--)
            for(int j=V2;j>=0;j--)
                if(i>=v1&&j>=v2)f[i][j]=max(f[i][j],f[i-v1][j-v2]+w);
    }
    cout<<f[V1][V2]<<endl;
    return ~~(0^_^0);
}

1020. 潜水员

暴力写挂了 这题数据真不水

大概是1600*1600*1000感觉可以卡着过的

这道题唯一区别就是状态计算吧

要是小于的话我们还是要算进去的吧

#include <bits/stdc++.h>
using namespace std;
const int N = 1610;
const int M = 1e4+10;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int f[N][N],n,V1,V2;
signed main(){
    fast
    cin>>V1>>V2>>n;
    memset(f,0x3f3f,sizeof f);
    f[0][0]=0;
    for(int i=1;i<=n;i++) {
        int v1, v2, w;
        cin >> v1 >> v2 >> w;
        for (int j = V1; j >= 0; j--)
            for (int k = V2; k >= 0; k--)
                f[j][k] = min(f[j][k], f[max(0, j - v1)][max(0, k - v2)] + w);
    }
    cout<<f[V1][V2]<<endl;
    return ~~(0^_^0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值