F. 来点每日一题
DP
由题容易想到的:
dp[i]表示 1-i 中求得的最大值, 所以最后ans为 dp[n]
状态转移与之前dp不一样的是,需要二维枚举,并且此题n的范围小,可以二维枚举:
dp[j]=max(dp[i-1]+cal(i,j),dp[j]);
cal(i,j)表示选 i~j 这个区间的最大值,如何计算? 还是DP
由于式子中有乘法,所以既要维护[i,j]区间的最大值,也要维护最小值
mx[i][j][1]=表示选了式子中的第一个数b1
状态转移:按选或不选第j个数划分
mx[i][j][1]=max(a[j],mx[i][j-1][1]);
mx[i][j][2]=max(mx[i][j-1][1]-a[j],mx[i][j-1][2]);
mx[i][j][3]=max(mx[i][j-1][2]*a[j],mx[i][j-1][3]);
mx[i][j][4]=max(mx[i][j-1][3]-a[j],mx[i][j-1][4]);
mx[i][j][5]=max(mx[i][j-1][4]*a[j],mx[i][j-1][5]);
mx[i][j][6]=max(mx[i][j-1][5]-a[j],mx[i][j-1][6]);
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define all(x) x.begin(),x.end()
#define no cout<<"No"<<endl
#define yes cout<<"Yes"<<endl
#define endl '\n'
// #define x first
// #define y second
typedef pair<int,int> PII;
const int N=200010;
const int mod=998244353;
const int INF=0x3f3f3f3f3f3f3f3f;
void solve(){
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
int mx[n+1][n+1][7]={};int mn[n+1][n+1][7]={};
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=1;k<=6;k++)
mx[i][j][k]=-INF,mn[i][j][k]=INF;
for(int i=1;i<=n;i++){
mx[i][i][1]=mn[i][i][1]=a[i];
for(int j=i+1;j<=n;j++){
for(int k=1;k<=6;++k)mx[i][j][k]=mx[i][j-1][k],mn[i][j][k]=mn[i][j-1][k];
mx[i][j][1]=max(a[j],mx[i][j][1]);
mn[i][j][1]=min(a[j],mn[i][j][1]);
if(mx[i][j-1][1]!=-INF)mx[i][j][2]=max(mx[i][j-1][1]-a[j],mx[i][j][2]);
if(mn[i][j-1][1]!=INF)mn[i][j][2]=min(mn[i][j-1][1]-a[j],mn[i][j][2]);
if(mx[i][j-1][2]!=-INF)mx[i][j][3]=max(mx[i][j-1][2]*a[j],mx[i][j][3]);
if(mn[i][j-1][2]!=INF)mx[i][j][3]=max(mn[i][j-1][2]*a[j],mx[i][j][3]);
if(mx[i][j-1][2]!=-INF)mn[i][j][3]=min(mx[i][j-1][2]*a[j],mn[i][j][3]);
if(mn[i][j-1][2]!=INF)mn[i][j][3]=min(mn[i][j-1][2]*a[j],mn[i][j][3]);
if(mx[i][j-1][3]!=-INF)mx[i][j][4]=max(mx[i][j-1][3]-a[j],mx[i][j][4]);
if(mn[i][j-1][3]!=INF)mn[i][j][4]=min(mn[i][j-1][3]-a[j],mn[i][j][4]);
if(mx[i][j-1][4]!=-INF)mx[i][j][5]=max(mx[i][j-1][4]*a[j],mx[i][j][5]);
if(mn[i][j-1][4]!=INF)mx[i][j][5]=max(mn[i][j-1][4]*a[j],mx[i][j][5]);
if(mx[i][j-1][4]!=-INF)mn[i][j][5]=min(mx[i][j-1][4]*a[j],mn[i][j][5]);
if(mn[i][j-1][4]!=INF)mn[i][j][5]=min(mn[i][j-1][4]*a[j],mn[i][j][5]);
if(mx[i][j-1][5]!=-INF)mx[i][j][6]=max(mx[i][j-1][5]-a[j],mx[i][j][6]);
if(mn[i][j-1][5]!=INF)mn[i][j][6]=min(mn[i][j-1][5]-a[j],mn[i][j][6]);
}
}
vector<int>dp(n+1);
for(int i=1;i<=n;i++){
dp[i]=max(dp[i-1],dp[i]);
for(int j=i+1;j<=n;j++){
dp[j]=max(dp[i-1]+mx[i][j][6],dp[j]);
}
}
cout<<dp[n]<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int _=1;
while(_--)solve();
return 0;
}
注意:若不写for(int k=1;k<=6;++k)mx[i][j][k]=mx[i][j-1][k],mn[i][j][k]=mn[i][j-1][k];
只写if(mx[i][j-1][2]!=-INF)mx[i][j][3]=max(mx[i][j-1][2]*a[j],mx[i][j-1][3]);是不行的
因为if判断为false的话, mx[i][j-1][3] 这个状态就不会被考虑。
空间优化
mx[j][7]表示,在当前遍历的 i~j 中所满足的最大值
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define all(x) x.begin(),x.end()
#define no cout<<"No"<<endl
#define yes cout<<"Yes"<<endl
#define endl '\n'
// #define x first
// #define y second
typedef pair<int,int> PII;
const int N=200010;
const int mod=998244353;
const int INF=0x3f3f3f3f3f3f3f3f;
void solve(){
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
vector<int>dp(n+1);
for(int i=1;i<=n;i++){
int mx[n+1][7]={};int mn[n+1][7]={};
for(int j=1;j<=n;j++)for(int k=1;k<=6;k++)
mx[j][k]=-INF,mn[j][k]=INF;
mx[i][1]=a[i],mn[i][1]=a[i];
for(int j=i+1;j<=n;j++){
for(int k=1;k<=6;++k)mx[j][k]=mx[j-1][k],mn[j][k]=mn[j-1][k];
mx[j][1]=max(a[j],mx[j][1]);
mn[j][1]=min(a[j],mn[j][1]);
if(mx[j-1][1]!=-INF)mx[j][2]=max(mx[j-1][1]-a[j],mx[j][2]);
if(mn[j-1][1]!=INF)mn[j][2]=min(mn[j-1][1]-a[j],mn[j][2]);
if(mx[j-1][2]!=-INF)mx[j][3]=max(mx[j-1][2]*a[j],mx[j][3]);
if(mn[j-1][2]!=INF)mx[j][3]=max(mn[j-1][2]*a[j],mx[j][3]);
if(mx[j-1][2]!=-INF)mn[j][3]=min(mx[j-1][2]*a[j],mn[j][3]);
if(mn[j-1][2]!=INF)mn[j][3]=min(mn[j-1][2]*a[j],mn[j][3]);
if(mx[j-1][3]!=-INF)mx[j][4]=max(mx[j-1][3]-a[j],mx[j][4]);
if(mn[j-1][3]!=INF)mn[j][4]=min(mn[j-1][3]-a[j],mn[j][4]);
if(mx[j-1][4]!=-INF)mx[j][5]=max(mx[j-1][4]*a[j],mx[j][5]);
if(mn[j-1][4]!=INF)mx[j][5]=max(mn[j-1][4]*a[j],mx[j][5]);
if(mx[j-1][4]!=-INF)mn[j][5]=min(mx[j-1][4]*a[j],mn[j][5]);
if(mn[j-1][4]!=INF)mn[j][5]=min(mn[j-1][4]*a[j],mn[j][5]);
if(mx[j-1][5]!=-INF)mx[j][6]=max(mx[j-1][5]-a[j],mx[j][6]);
if(mn[j-1][5]!=INF)mn[j][6]=min(mn[j-1][5]-a[j],mn[j][6]);
dp[j]=max(dp[i-1]+mx[j][6],dp[j]);
}
}
cout<<dp[n]<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int _=1;
while(_--)solve();
return 0;
}
甚至还能用滚动数组继续优化
mx[7]表示,在当前遍历的 i~j 中所满足的最大值
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define all(x) x.begin(),x.end()
#define no cout<<"No"<<endl
#define yes cout<<"Yes"<<endl
#define endl '\n'
// #define x first
// #define y second
typedef pair<int,int> PII;
const int N=200010;
const int mod=998244353;
const int INF=0x3f3f3f3f3f3f3f3f;
void solve(){
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
vector<int>dp(n+1);
for(int i=1;i<=n;i++){
vector<int>mx1(7,-INF),mn1(7,INF);
mx1[1]=mn1[1]=a[i];
for(int j=i+1;j<=n;j++){
vector<int>mx=mx1,mn=mn1;
mx[1]=max(a[j],mx[1]);
mn[1]=min(a[j],mn[1]);
if(mx1[1]!=-INF)mx[2]=max(mx1[1]-a[j],mx[2]);
if(mn1[1]!=INF)mn[2]=min(mn1[1]-a[j],mn[2]);
if(mx1[2]!=-INF)mx[3]=max(mx1[2]*a[j],mx[3]);
if(mn1[2]!=INF)mx[3]=max(mn1[2]*a[j],mx[3]);
if(mx1[2]!=-INF)mn[3]=min(mx1[2]*a[j],mn[3]);
if(mn1[2]!=INF)mn[3]=min(mn1[2]*a[j],mn[3]);
if(mx1[3]!=-INF)mx[4]=max(mx1[3]-a[j],mx[4]);
if(mn1[3]!=INF)mn[4]=min(mn1[3]-a[j],mn[4]);
if(mx1[4]!=-INF)mx[5]=max(mx1[4]*a[j],mx[5]);
if(mn1[4]!=INF)mx[5]=max(mn1[4]*a[j],mx[5]);
if(mx1[4]!=-INF)mn[5]=min(mx1[4]*a[j],mn[5]);
if(mn1[4]!=INF)mn[5]=min(mn1[4]*a[j],mn[5]);
if(mx1[5]!=-INF)mx[6]=max(mx1[5]-a[j],mx[6]);
if(mn1[5]!=INF)mn[6]=min(mn1[5]-a[j],mn[6]);
dp[j]=max(dp[i-1]+mx[6],dp[j]);
mx1=mx;
mn1=mn;
}
}
cout<<dp[n]<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int _=1;
while(_--)solve();
return 0;
}
文章讲述了如何使用动态规划方法解决一个涉及区间最大值的问题,包括状态转移方程的更新和空间优化策略,如使用一维数组、二维数组以及滚动数组来降低空间复杂度。最后提到与K.方块掉落问题的关联,可能是题目来源或者应用实例。
428





