求满足某一要求的最长序列是多长。
显然是最大上升子序列。
把每一个坐标存在 pair 里,排序后即可保证
x
x
x 单调不降,判断
y
y
y 是否同样单调不降即可。
设状态 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个点中加了 j j j 个自由点后的最长串。
转移直接枚举从哪个点转移过来,中间需要加的点就是两点之间距离减去 1 1 1。
然后再枚举用了多少个自由点,暴力转移即可。
最后有一个细节,我并不知道用了多少个自由点和在哪个点结束,所以要枚举,最后还要把剩下的自由点加上。
完结撒花。
#include
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); ++(i))
#define fep(i, a, b) for (int (i) = (a); (i) < (b); ++(i))
#define int long long
#define N 507
using namespace std;
int n;
int k;
int ans;
int dp[N][N];
int ep[N][N];
pair <int, int> p[N];
signed main() {
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= n; ++i)
scanf("%lld%lld", &p[i].first, &p[i].second);
sort(p + 1, p + n + 1);
for (int i = 0; i <= N - 1; ++i)
dp[i][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; j ++)
ep[i][j] = abs(p[i].first - p[j].first) + abs(p[i].second - p[j].second) - 1;
sort(p + 1, p + n + 1);
for (int t = 0; t <= k; ++t)
for (int i = 1; i <= n; ++i)
for (int j = 1; j < i; ++j)
if (p[i].second >= p[j].second && t >= ep[i][j])
dp[i][t] = max <int> (dp[i][t], dp[j][t - ep[i][j]] + ep[j][i] + 1);
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= k; ++j)
ans = max <int> (ans, dp[i][j] + k - j);
printf("%lld\n", ans);
return 0;
}