题解
2025-03-23 23:13:17
发布于:广东
37阅读
0回复
0点赞
首先来一个正常的 DP:
记录在第 格,当 时收集宝石的最大值。
显然递推式如下:
其中 为第 格的宝石数,并且要保证 。
#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
int a[5005], b[5005], dp[5005][5005];
int n, m, mx;
signed main(){
memset(dp, -64, sizeof(dp));
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i], b[a[i]]++;
dp[m][m] = b[m];
for(int i = m + 1; i <= 5000; i++){
for(int j = 1; j <= i - m; j++){
dp[i][j] = max(max(dp[i - j][j - 1], dp[i - j][j]), dp[i - j][j + 1]) + b[i];
mx = max(mx, dp[i][j]);
}
}
cout << mx;
return 0;
}
时间复杂度:。
得分:。
这对于 的数据还是太吃操作了,怎么优化呢?
注意到在 格内,跳跃过程中 的取值范围很小,一定在 的范围内,也就是说上面的 存在大量无效状态。
根据上面的推理,我们可以把 的第二维的大小减少到 , 表示第 格,当 时收集宝石的最大值。将上面的状态转移方程稍加改变即可。
#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
int a[30005], b[30005], dp[30005][615];
//(d-300)~(d+300)
int n, m, mx;
signed main(){
memset(dp, -64, sizeof(dp));
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i], b[a[i]]++;
dp[m][301] = b[m];
for(int i = m + 1; i <= 30000; i++){
for(int j = 1; j <= 601; j++){
int realj = j + m - 301;
if(realj < 1 || realj > i) continue;
dp[i][j] = max(max(dp[i - realj][j - 1], dp[i - realj][j]), dp[i - realj][j + 1]) + b[i];
mx = max(mx, dp[i][j]);
}
}
cout << mx;
return 0;
}
时间复杂度:。
得分:。
这里空空如也
有帮助,赞一个