3 条题解
-
9
这是一道经典的动态规划问题,使用状态转移方程求解。
首先,我们定义一个二维数组
f
,其中f[i][j]
表示考虑前i
个数,去掉j
个数后,最多能有多少个数在正确位置上。接下来,使用两层循环遍历所有可能的状态。外层循环控制考虑的数的个数
i
,从 1 到n
。内层循环控制去掉的数的个数j
,从 0 到i
。在每个状态
(i, j)
下,有两种选择:- 如果
i-1
大于等于j
,则可以选择将第i
个数保留在正确位置上(即a[i] == i - j
),则f[i][j]
的值为f[i-1][j]
加上保留的数量。 - 如果
j
大于 0,则可以选择不保留第i
个数,此时f[i][j]
的值为f[i-1][j-1]
。
在每次选择后,更新
f[i][j]
的值为两种选择中较大的那个。最终,遍历所有状态
(n, j)
,找到最大的f[n][j]
,即为擦除某些数后剩下的数列中最多能有多少个数在正确位置上。综上,状态转移方程如下:
其中,
[a[i] = i-j]
是一个布尔值,表示第i
个数是否在正确位置上。这里使用了一种简洁的写法,即当a[i] = i-j
时,[a[i] = i-j]
的值为 1,否则为 0。根据状态转移方程,我们可以编写对应的代码实现。
#include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; ++i) { cin >> a[i]; } vector<vector<int>> f(n + 1, vector<int>(n + 1, 0)); for (int i = 1; i <= n; ++i) { for (int j = 0; j <= i; ++j) { if (i - 1 >= j) f[i][j] = max(f[i][j], f[i - 1][j] + (a[i] == i - j)); if (j > 0) f[i][j] = max(f[i][j], f[i - 1][j - 1]); } } int ans = 0; for (int i = 0; i <= n; ++i) { ans = max(ans, f[n][i]); } cout << ans << endl; return 0; }
- 如果
-
1
这是一道动态规划问题。
首先,我们定义一个二维数组
f
,f[i][j]
表示考虑前i
个数,去掉j
个数后,最多能有多少个数在正确位置上。接下来,用两层循环遍历所有可能的状态。外层循环控制考虑的数的个数
i
,从 1 到n
。内层循环控制去掉的数的个数j
,从 0 到i
。每个状态
(i, j)
下,有两种选择:- 如果
i-1
大于等于j
,则可以选择将第i
个数保留在正确位置上(即a[i] == i - j
),则f[i][j]
的值为f[i-1][j]
加上保留的数量。 - 如果
j
大于 0,则可以选择不保留第i
个数,此时f[i][j]
的值为f[i-1][j-1]
。
每次选择后,都更新
f[i][j]
的值为两种选择中最大的那个。最终,遍历所有状态
(n, j)
,找到最大的f[n][j]
,即为擦除某些数后剩下的数列中最多能有多少个数在正确位置上。状态转移方程如下:
编写循环时可用f[i][j]去表示考虑前i个数,**去掉j个数后,最多有多少个数在正确位置上。**前i个数去掉j个后,a[i]就在第i-j个位置上,如果a[i]等于i-j,说明它在正确位置上。 代码如下:
#include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; ++i) { cin >> a[i]; } vector<vector<int>> f(n + 1, vector<int>(n + 1, 0)); for (int i = 1; i <= n; ++i) { for (int j = 0; j <= i; ++j) { if (i - 1 >= j) f[i][j] = max(f[i][j], f[i - 1][j] + (a[i] == i - j)); if (j > 0) f[i][j] = max(f[i][j], f[i - 1][j - 1]); } } int ans = 0; for (int i = 0; i <= n; ++i) { ans = max(ans, f[n][i]); } cout << ans << endl; return 0; }
代码按课程里编写代码的话,思路代码都是这样的。 照课里面讲的和书里的做很简单。
- 如果
-
1
可以用f[i][j]表示考虑前i个数,去掉j个数后,最多能有多少个数在正确位置上。前i个数去掉j个后,a[i]数在第i-j个位置上,如果a[i]等于i-j,说明它在正确位置上。状态转移方程见代码。
核心代码
for (int i = 1; i <= n; i++) { for (int j = 0; j <= i; j++) { if (i - 1 >= j) f[i][j] = max(f[i][j], f[i - 1][j] + (a[i] == i - j)); if (j > 0) f[i][j] = max(f[i][j], f[i - 1][j - 1]); } } for (int i = 0; i <= n; i++) ans = max(ans, f[n][i]);
- 1
信息
- ID
- 380
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- (无)
- 递交数
- 349
- 已通过
- 222
- 上传者