题目大意
如题
分析
设最佳通关方案为 { s 1 , s 2 , . . . , s k } \{s_1,s_2,...,s_k\} {s1,s2,...,sk},其中 s i s_i si 代表第 i i i 次到达的关卡( ≥ N \ge N ≥N 的不算)。
-
当 a k = N − 1 a_k=N-1 ak=N−1 时,方案变为 { s 1 , s 2 , . . . , s k − 1 , N − 1 } \{s_1,s_2,...,s_{k-1},N-1\} {s1,s2,...,sk−1,N−1}。
方案的属性:- 总分。原方案的总分 = 子方案的总分+ b N − 1 b_{N-1} bN−1。由于,原方案要求解的是最高总分。因此,子方案要求解的也是最高总分。
- 目的地。子方案的目的地变为 N − 1 N-1 N−1。
综上:子方案反映的问题是目的地为 N − 1 N-1 N−1,能够获得的最高总分?
-
当 a k = N − 2 a_k=N-2 ak=N−2 时,方案变为 { s 1 , s 2 , . . . , s k − 1 , N − 2 } \{s_1,s_2,...,s_{k-1},N-2\} {s1,s2,...,sk−1,N−2}。
方案的属性:- 总分。原方案的总分 = 子方案的总分+ b N − 2 b_{N-2} bN−2。由于,原方案要求解的是最高总分。因此,子方案要求解的也是最高总分。
- 目的地。子方案的目的地变为 N − 2 N-2 N−2。
综上:子方案反映的问题是目的地为 N − 2 N-2 N−2,能够获得的最高总分?
⋮ \vdots ⋮ -
当 a k = 1 a_k=1 ak=1 时,方案变为 { s 1 , s 2 , . . . , s k − 1 , 1 } \{s_1,s_2,...,s_{k-1},1\} {s1,s2,...,sk−1,1}。
方案的属性:- 总分。原方案的总分 = 子方案的总分+ b 1 b_1 b1。由于,原方案要求解的是最高总分。因此,子方案要求解的也是最高总分。
- 目的地。子方案的目的地变为 1 1 1。
综上:子方案反映的问题是目的地为 1 1 1,能够获得的最高总分?
需要注意的是,这些子问题的合法需满足:存在这么一个通道,可以从子方案的目的地,直接到达 ≥ N \ge N ≥N 的地方。
因为,原问题不存在这么一个准确的目的地,这与子问题不符合。所以,我们需要将超过 N N N 的情况,拆解为:到达 N + 1 N+1 N+1, N + 2 N+2 N+2,…, 2 N 2N 2N 的问题(之所以是 2 N 2N 2N 是因为, a i ≤ N a_i\le N ai≤N)。
现在,所有的问题都变为:目的地为 i i i,能够获得的最高总分?
对其方案重新进行分析:
-
当 a k = j a_k=j ak=j 时,方案变为 { s 1 , s 2 , . . . , s k − 1 , j , i } \{s_1,s_2,...,s_{k-1},j,i\} {s1,s2,...,sk−1,j,i}。
方案的属性:- 总分。原方案的总分 = 子方案的总分+ b j b_j bj。由于,原方案要求解的是最高总分。因此,子方案要求解的也是最高总分。
- 目的地。子方案的目的地变为 j j j。
综上:子方案反映的问题是目的地为 j j j,能够获得的最高总分?
需要注意的是,必须存在一种通道使得 j j j 能够到达 i i i 这种情况才合法。因此,直接通过枚举所有通道,就可以获得所有合法情况。
问题的状态: d p i dp_i dpi 代表目的地为 i i i,能够获得的最高总分?
状态转移式: d p i = max ( d p i − a j + b j ) ( 1 ≤ j ≤ m ) dp_i=\max(dp_{i-a_j}+b_j)(1\le j \le m) dpi=max(dpi−aj+bj)(1≤j≤m)
问题的初始化: d p 0 = 0 dp_0=0 dp0=0
问题的答案: max ( d p i ) ( n + 1 ≤ i ≤ 2 n ) \max(dp_i)(n+1\le i \le2n) max(dpi)(n+1≤i≤2n)。
示例程序
#include<iostream>
#include<algorithm>using namespace std;const int N = 1e4 + 10;int a[N],b[N * 2],dp[N * 2];int main(){int n,m;cin >> n >> m;for(int i = 0; i <= m - 1; i++){cin >> a[i];}for(int i = 0; i <= n - 1; i++){cin >> b[i];}for(int i = 0; i <= 2 * n; i++) dp[i] = -1e9;dp[0] = 0;int maxn = -1e9;for(int i = 1; i <= 2 * n - 1; i++){for(int j = 0; j <= m - 1; j++){if(i - a[j] >= 0){dp[i] = max(dp[i],dp[i - a[j]] + b[i - a[j]]);}}if(i >= n){maxn = max(maxn,dp[i]);}}cout << maxn;return 0;
}