2023牛客暑期多校训练营2(K题Box)dp

链接:登录—专业IT笔试面试备考平台_牛客网

题目:

 题意:

有n个盒子,并且给定每个盒子上是否有盖子,每个盖子都只能向左或向右最多移动一个位置,求有盖子的盒子上的值的和最大是多少

思路:

由于是给定的n的范围,所以最多两种时间复杂度,O(nlogn)或者O(n)的算法进行求解,由于是线性关系,所以可以尝试遍历一遍进行存储不同状态下的值进行dp;

dp[i][0]:表示1到i位置 ,最右边为0的最大值;

dp[i][1]:表示 1到i位置,最右边为可以动的1的情况的最大值; 

dp[i][2]:表示~~~~~~~,最右边为不可以动的1的情况(相当于是从前面i-1位置的1转移到i位置的情况)的最大值;

dp[i][3]:表示~~~~~~~,最右边为两个1的情况(相当于前面i-1的位置的1转移到了i,而i位置也是1的情况)的最大值;

最大值就是答案所要求的最大值,只是1到n的最大值为最终的答案;

转移方程主要是分为4种情况:

每种情况的0,1,前面一个数表示i-1的是否有盖子的值,后一个数表示i的位置是否有盖子的值;

第一种为(i-1,i)0 0:无需转移,但需要保留前面几种情况的最大值;

第二种  0 1:1可以往前移的情况;

第三种:1 1:i-1位置有两个1的情况向i位置转移,或者将右边的1向前转移更新dp[i][0]的值;

第四种:1 0: 1向后进行转移,有两种情况,一种i-1的位置含有两个1的情况,一种只含有一个1的情况,进行向后转移;

不需要进行移动的,也需要保留之前几种情况的最大值更新;

以上是大致思路:可以看完思路后自己进行实现,试一试或许自己就能搞定了,比赛的时候改了好久才改对的,竟然这么多种情况也搞定了;

#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
typedef pair<int,int> pr;

#define int long long
#define fr(i,l,r) for(int i=l;i<=r;i++)
#define pb(x) push_back(x)
#define all(a) a.begin(),a.end()
#define fi first
#define se second

const int N = 1e6+10;
const int mod=998244353,inf=LONG_LONG_MAX;
int dx[]={0,0,-1,0,1},dy[]={0,-1,0,1,0};
int n,m;

int a[N],b[N];
int dp[N][4];
int dp2[N][4];

void solve()
{
    cin>>n;
    fr(i,1,n) cin>>a[i];
    fr(i,1,n) cin>>b[i];

    int mx=0;
    fr(i,1,n)
    {
        if(b[i-1]==0&&b[i]==0)
        {
            dp[i][0]=mx;    //保留之前的最大值进行更新
        }
        if(b[i-1]==0&&b[i]==1)
        {
            dp[i][0]=dp[i-1][0]+a[i-1];//i位置的1向前移i位置变为0,更新i位置为0的情况
            dp[i][1]=mx+a[i];          //保留之前的最大值进行更新
        }
        else if(b[i-1]==1&&b[i]==1)
        {
            dp[i][3]=max(dp[i-1][1]-a[i-1]+a[i],dp[i-1][3]+a[i]);//更新i-1位置向后移动i位置为两个1的情况
            dp[i][0]=max(dp[i][0],dp[i-1][0]+a[i-1]);            //更新向前移动后i位置为0的情况
            dp[i][1]=mx+a[i];//保留之前的最大值进行更新
        }
        else if(b[i-1]==1&&b[i]==0)
        {
            dp[i][2]=max(dp[i-1][3]+a[i],dp[i-1][1]-a[i-1]+a[i]);//更新前面的1向后移动的情况;移动后i位置为1,是不能再进行移动的情况所以更新dp[i][2]的状态;
            dp[i][0]=mx;//保留之前的最大值进行更新
        }
        fr(j,0,3) mx=max(mx,dp[i][j]);
    }
    cout<<mx<<endl;
}
signed main()
{
//    ios;
    int t=1;
    //cin>>t;
    while(t--) solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值