Files
python/TangDou/CSP-J/AcWingTraining/T7/4731.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

71 lines
2.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int N = 510;
const int M = 110;
struct Node {
int x, y;
/*
Q1:为什么要排序?
A:因为要DP,需要解决无后效性。也就是有一定的单调性,从左向右,从上向下填表,填完的数值不能再被修改,需要有一定的依赖关系顺序
Q2:按什么来排序?
A:可以按x+y来排序,也可以按先x,后y的方式来排序,都是一样的。
1.按x+y排序
const bool operator<(const Node &t) {
return x + y < t.x + t.y;
}
*/
// 2.先按x,再按y排序
const bool operator<(const Node &t) {
if (x == t.x) return y < t.y;
return x < t.x;
}
} a[N];
int f[N][M];
int ans;
int main() {
// 文件输入
// freopen("point.in", "r", stdin);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i].x >> a[i].y;
sort(a + 1, a + 1 + n);
// dp初始化,最后一个点是以i号点选中,并且,使用了j个虚拟点情况下,获得的最长序列长度
for (int i = 1; i <= n; i++)
for (int j = 0; j <= m; j++)
f[i][j] = j + 1; // 以i点结束,并且,使用了j个虚拟点,最起码可以构成一个最长长度为j+1的序列
// 状态转移
for (int i = 1; i <= n; i++) // 枚举每个原始点
for (int j = 1; j < i; j++) { // 枚举每个前序点
if (a[i].x < a[j].x || a[i].y < a[j].y) continue; // 如果j不在i的左下方,无效转移
int d = a[i].x - a[j].x + a[i].y - a[j].y - 1; // j->i 需要增加的虚拟点个数
/*
讨论j点的哪些子状态 可以转移到 i的哪些子状态?
思考一下f[j]的二维状态,最小值是0,最大值是m
现在f[j]的二维状态变化量是固定的,是d
所以需要枚举j的所有以转移的二维状态值:0 ~ m-d
*/
for (int k = 0; k <= m - d; k++) {
// f[j][k]是前序状态,可以通过+d转移到新的状态
// f[j][k+d]+d+1 -> f[i][k+d]
f[i][k + d] = max(f[i][k + d], f[j][k] + d + 1);
// 在状态转移完成后,收集一下答案
// 小坑一个:给你m个虚拟点,你最后没用了的话,就是浪费,因为最起码,
// 把多出来的放在最后就可以增长序列长度
ans = max(ans, f[i][k + d] + m - k - d); // 更新序列最长长度
}
}
// 输出结果
printf("%d\n", ans);
return 0;
}