【CSP-J 2022】上升点列

【CSP-J 2022】上升点列 解题报告

1 题目大意

求满足某一要求的最长序列是多长。

2 题目分析

显然是最大上升子序列。

把每一个坐标存在 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

然后再枚举用了多少个自由点,暴力转移即可。

最后有一个细节,我并不知道用了多少个自由点和在哪个点结束,所以要枚举,最后还要把剩下的自由点加上。

完结撒花。

3 AC Code

#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;
}

你可能感兴趣的:(CCF,题解,动态规划,算法)