描述
题解
十分不错的dp,需要考虑到空间优化问题,否则会爆炸~~~可以使用偏移量的方法(One),也可以预处理跳跃的区间(Two)。当然方法多种多样,貌似使用记忆化搜索也可以过。
代码
One:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int MAXN = 3e4 + 5;
const int MAXM = 500;
int res;
int n, d, pos;
int land[MAXN];
int dp[MAXN][MAXM]; // dp[i][j]表示走到第i个岛,上一步是j所捡的宝石数量
void input()
{
int stone;
pos = 0;
scanf("%d%d", &n, &d);
for (int i = 1; i < n; i++)
{
scanf("%d", &stone);
land[stone]++;
}
scanf("%d", &pos);
land[pos]++;
return ;
}
void solve()
{
memset(dp, -1, sizeof(dp));
int mid = MAXM / 2; // 空间优化,mid是偏移值
dp[d][mid] = land[d];
for (int i = d; i <= pos; i++)
{
for (int j = 0; j < MAXM; j++)
{
if (dp[i][j] >= 0)
{
int next = d + j - mid;
for (int k = -1; k <= 1; k++)
{
if (next + k >= 1 && i + next + k <= pos)
{
dp[i + next + k][j + k] = max(dp[i + next + k][j + k], dp[i][j] + land[i + next + k]);
}
}
}
}
}
res = 0;
for (int i = d; i <= pos; i++)
{
for (int j = 0; j <= MAXM; j++)
{
res = max(res, dp[i][j]);
}
}
printf("%d", res);
}
int main()
{
input();
solve();
return 0;
}
Two:
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 3e4 + 1;
int val[MAXN];
void solve()
{
int n, d;
scanf("%d%d", &n, &d);
for (int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
val[x]++;
}
int min_d, max_d, sum;
sum = min_d = d;
while (sum < MAXN && min_d > 1)
{
sum += --min_d;
}
sum = max_d = d;
while (sum < MAXN)
{
sum += ++max_d;
}
vector<vector<int> > dp(MAXN, vector<int> (max_d - min_d + 1));
// 从尾向前推
for (int i = MAXN - 1; i >= d; i--)
{
for (int j = min_d; j <= max_d; j++)
{
int tmp = 0;
if (i + j - 1 < MAXN && j != min_d)
{
tmp = max(tmp, dp[i + j - 1][j - 1 - min_d]);
}
if (i + j < MAXN)
{
tmp = max(tmp, dp[i + j][j - min_d]);
}
if (i + j + 1 < MAXN && j != max_d)
{
tmp = max(tmp, dp[i + j + 1][j + 1 - min_d]);
}
dp[i][j - min_d] = tmp + val[i];
}
}
printf("%d\n", dp[d][d - min_d]);
}
int main()
{
solve();
return 0;
}