2023牛客暑期多校训练营5-H Nazrin the Greeeeeedy Mouse
https://ac.nowcoder.com/acm/contest/57359/H
题意
解题思路
这显然要用到dp,先不管时间复杂度,考虑转移的状态与方程式,定义
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示从
i
i
i点走到
j
j
j点在背包容量为
k
k
k时所能取到的最大重量,是一个简单的01背包,再定义
d
p
i
,
j
dp_{i,j}
dpi,j表示第
i
i
i次操作走到第
j
j
j个点所能取到的最大重量,可得转移方程式为
d
p
i
,
j
=
M
a
x
k
=
1
j
{
d
p
i
−
1
,
k
+
f
i
,
j
,
s
z
i
}
dp_{i,j}=Max_{k=1}^{j}\{dp_{i-1,k}+f_{i,j,sz_i}\}
dpi,j=Maxk=1j{dpi−1,k+fi,j,szi}
时间复杂度为
O
(
n
2
m
)
O(n^2m)
O(n2m),题目中还有一个条件:保证对于
i
>
1
i>1
i>1,有
s
z
i
≥
s
z
i
−
1
sz_i\ge sz_{i-1}
szi≥szi−1。显然当
m
>
n
m>n
m>ns时,对于前面的
s
z
sz
sz,最后
n
n
n个
s
z
sz
sz所能得到的结果更优,所以实质上只需计算最后
n
n
n个
s
z
sz
sz即可,复杂度为
O
(
n
3
)
O(n^3)
O(n3)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
long long n,m,a[205],b[205],sz[N],f[205][205][205],dp[100005][205];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
for(int i=1;i<=m;i++)cin>>sz[i];
for(int i=0;i<n;i++)
for(int j=i+1;j<=n;j++){
for(int k=0;k<=200;k++)f[i][j][k]=f[i][j-1][k];
for(int k=a[j];k<=200;k++){
f[i][j][k]=max(f[i][j][k],f[i][j-1][k-a[j]]+b[j]);
}
}
for(int i=1;i<=min(m,n);i++){
for(int j=1;j<=n;j++)
for(int k=0;k<j;k++)
dp[i][j]=max(dp[i][j],dp[i-1][k]+f[k][j][sz[i+max(0ll,m-n)]]);
}
long long sum=0;
for(int i=1;i<=n;i++)sum=max(dp[min(m,n)][i],sum);
cout<<sum;
}