专栏文章
题解:P11876 收徒!
P11876题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipy3zfi
- 此快照首次捕获于
- 2025/12/03 19:50 3 个月前
- 此快照最后确认于
- 2025/12/03 19:50 3 个月前
题目大意
给定一个 的空白方格,从中选出 个点附上 的价值。问从 走到 只能向下和向右前行,所能获得的最大价值,并输出路径。
解题思路
部分分思路
很容易想到坐标动态规划,然后用数组记录每次决策的转移方向。但是 和 很大不能开这么大的数组,否则会炸空间。
代码如下:
C#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+5;
int h, w, n, x, y;
int dp[N][N], mp[N][N];
char pre[N][N];
void dfs(int x, int y) {
if (x == 1 && y == 1) return ;
if (pre[x][y] == 'D') dfs(x - 1, y);
else dfs(x, y - 1);
cout << pre[x][y];
}
int main() {
cin >> h >> w >> n;
for (int i = 1; i <= n; i++) {
cin >> x >> y;
mp[x][y] = 1;
}
for (int i = 2; i <= n; i++)
dp[i][1] = dp[i - 1][1] + mp[i][1], pre[i][1] = 'D';
for (int j = 2; j <= w; j++)
dp[1][j] = dp[1][j - 1] + mp[1][j], pre[1][j] = 'R';
for (int i = 2; i <= h; i++)
for (int j = 2; j <= w; j++) {
if (dp[i - 1][j] > dp[i][j - 1]) {
pre[i][j] = 'D';
dp[i][j] = dp[i - 1][j] + mp[i][j];
} else {
pre[i][j] = 'R';
dp[i][j] = dp[i][j - 1] + mp[i][j];
}
}
cout << dp[h][w] << endl;
dfs(h, w);
return 0;
}
满分思路
考虑到数据范围很大,显然不能直接坐标动态规划。由于只能向下向右并且价值为 。 可以考虑把问题转换为最长不下降子序列问题,用效率为 的贪心和二分方法计算答案。即从 个按 坐标从小到大排序的点中找到一条最长的一条链。答案可以直接构造。
C#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int h, w, n, c[N], dp[N], nowx[N], nowy[N], k;
int pre[N]; //记录第i个数的前一项的下标
int lst[N]; //记录长度为len的最后一项的下标
string ans;
struct node {
int x, y;
bool operator<(node &b) {
if (x == b.x) return y < b.y;
return x < b.x;
}
} a[N];
void dfs(int now) {
if (now == 0) return;
dfs(pre[now]);
++k;
nowx[k] = a[now].x, nowy[k] = a[now].y;
}
int main() {
cin >> h >> w >> n;
for (int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y;
sort(a + 1, a + 1 + n);
dp[1] = a[1].y;
lst[1] = 1, pre[1] = 0;
int len = 1;
for (int i = 2; i <= n; i++) {
if (dp[len] <= a[i].y) { //如果这一项能接在最长的一项后面
pre[i] = lst[len]; //当前项的前驱为之前长度为len的最小的最长项
dp[++len] = a[i].y; //记录当前长度为len的子序列的最后一项
lst[len] = i; //记录当前长度为len的最后一项的下标
} else {
int x = upper_bound(dp + 1, dp + 1 + len, a[i].y) - dp; //查找等于len的
pre[i] = lst[x - 1];
dp[x] = a[i].y;
lst[x] = i;
}
}
cout << len << endl;
nowx[1] = nowy[1] = k = 1;
dfs(lst[len]); //递归记录路径
++k, nowx[k] = h, nowy[k] = w;
for (int i = 2; i <= k; i++) { //根据曼哈顿距离构造答案
string D(nowx[i] - nowx[i - 1], 'D');
string R(nowy[i] - nowy[i - 1], 'R');
ans += D + R;
// cout << nowx[i] << " " << nowy[i] << endl;
}
cout << ans;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...