2021-07-25(动态规划)
作者:互联网
链接:https://ac.nowcoder.com/acm/problem/15553
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
今天qwb要参加一个数学考试,这套试卷一共有n道题,每道题qwb能获得的分数为ai,qwb并不打算把这些题全做完,
他想选总共2k道题来做,并且期望他能获得的分数尽可能的大,他准备选2个不连续的长度为k的区间,
即[L,L+1,L+2,…,L+k-1],[R,R+1,R+2,…,R+k-1](R >= L+k)。
输入描述:
第一行一个整数T(T<=10),代表有T组数据
接下来一行两个整数n,k,(1<=n<=200,000),(1<=k,2k <= n)
接下来一行n个整数a1,a2,…,an,(-100,000<=ai<=100,000)
输出描述:
输出一个整数,qwb能获得的最大分数
示例1
输入
复制
2
6 3
1 1 1 1 1 1
8 2
-1 0 2 -1 -1 2 3 -1
输出
复制
6
7
这个题是一个dp加前缀和的题目。思想是用dp维护i点右边区间最大的连续的长度为k的子区间分值,这就要求维护的时候从右边开始,然后枚举当前节点,不断更新ans
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200005;
ll s[N];
ll maxi[N];
ll a[N];
int n,k;
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>k;
memset(a,0,sizeof(a));
memset(maxi,-1e4,sizeof(maxi));
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];
}
for(int i=n-k+1;i>=1;i--){
maxi[i]=max(maxi[i+1],s[i+k-1]-s[i-1]);
}
ll ans=-1e18;
for(int i=k;i<=n-k;i++)
ans=max(ans,s[i]-s[i-k]+maxi[i+1]);
cout<<ans<<endl;
}
return 0;
}
链接:https://ac.nowcoder.com/acm/problem/20242
来源:牛客网
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。
注意:选出的k个子矩阵 不能相互重叠。
输入描述:
第一行为n,m,k(1 ≤ n ≤ 100,1 ≤ m ≤ 2,1 ≤ k ≤ 10),
接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
输出描述:
只有一行为k个子矩阵分值之和最大为多少。
示例1
输入
复制
3 2 2
1 -3
2 3
-2 3
输出
复制
9
这道题和上面一个有点类似,不过是根据数据范围我们设计一个
dp[i][j][k]表示第一列前i个,第二列前j个,选择k个子矩阵获得的最大值
那么实际上有四种情况。
由于要求不能重叠,我们维护方式就有所变化,但本质不会变
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=105;
const int M=15;
int dp[N][N][M];
int sq[N][3];
int n,m,k;
int sum[N][3];//第j列前i项前缀和
int main(){
cin>>n>>m>>k;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){//
for(int j=1;j<=m;j++){
scanf("%d",&sq[i][j]);
sum[i][j]=sum[i-1][j]+sq[i][j];//维护前缀
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int z=1;z<=k;z++){
dp[i][j][z]=max(dp[i][j-1][z],dp[i-1][j][z]);
for(int l=0;l<i;l++)
dp[i][j][z]=max(dp[l][j][z-1]+sum[i][1]-sum[l][1],dp[i][j][z]);
for(int l=0;l<j;l++)
dp[i][j][z]=max(dp[i][l][z-1]+sum[j][2]-sum[l][2],dp[i][j][z]);
if(i==j){//相等是特殊情况,前面的一般性的判断要继续执行
for(int l=0;l<i;l++)
dp[i][j][z]=max(dp[l][l][z-1]+sum[i][1]-sum[l][1]+sum[j][2]-sum[l][2],dp[i][j][z]);
}
}
}
}
cout<<dp[n][n][k]<<endl;
return 0;
}
上面两题的思想和我之前做的硬币组合思想很像,但硬币组合不涉及前缀和。
标签:25,07,int,ll,矩阵,maxi,2021,include,dp 来源: https://blog.csdn.net/weixin_52829980/article/details/119082282