题目:
题意:
有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;
}