1.题目描述
题目传送门 - Atcoder Beginner Contest369 D题题面
2.题意转化
给你 n n n 个数 a i ( 1 ≤ i ≤ n ) a_i \ (1 \leq i \leq n) ai (1≤i≤n) ,每个数可以选或不选。对于每一个选的数 a j a_j aj ,如果是从左往右第偶数个数,那么答案增加 a j ∗ 2 ( j m o d 2 = 0 ) a_j*2 \ (j \mod 2 = 0) aj∗2 (jmod2=0) ;否则答案增加 a j ( j m o d 2 = 1 ) a_j \ (j \mod 2 = 1) aj (jmod2=1) 。
3.思路分析
对于每一个数 a i a_i ai ,都存在选或不选两种情况。这样我们很容易想到动态规划的0/1背包。
仔细一想,如果用0/1背包,需要用 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示对于前 i i i 个数,选其中的 j j j 个。 k = 0 k = 0 k=0 表示不选第 i i i 个数, k = 1 k = 1 k=1 表示选第 i i i 个数。则有递推式: d p [ i ] [ j ] [ 0 ] = m a x ( d p [ i − 1 ] [ j ] [ 0 ] , d p [ i − 1 ] [ j ] [ 1 ] ) dp[i][j][0] = max(dp[i-1][j][0],dp[i-1][j][1]) dp[i][j][0]=max(dp[i−1][j][0],dp[i−1][j][1]) d p [ i ] [ j ] [ 1 ] = m a x ( d p [ i − 1 ] [ j − 1 ] [ 0 ] , d p [ i − 1 ] [ j − 1 ] [ 1 ] ) + a i + ( j m o d 2 ) ∗ a i dp[i][j][1] = max(dp[i-1][j-1][0],dp[i-1][j-1][1])+a_i+(j\mod2)*a_i dp[i][j][1]=max(dp[i−1][j−1][0],dp[i−1][j−1][1])+ai+(jmod2)∗ai
以上两个式子比较好理解,根据 j j j 的取值即可判断这是不是所选的第偶数个数字。
但是存在问题:
- 空间复杂度 O ( n 2 ) O(n^2) O(n2) ,除非在Atcoder否则不能通过此题。
- 时间复杂度,需要枚举 i , j , k i,j,k i,j,k ,时间复杂度 O ( n 2 ) O(n^2) O(n2) ,无法通过此题。
我们考虑dp的核心:不就是维护第 i i i 个数是所选的第几个数吗!
并且我们只关心所选的是不是第偶数个数,即设 b j b_j bj 是所选的第 j j j 个数,关键是维护 j m o d 2 = 0 j\mod2 = 0 jmod2=0 和 j m o d 2 = 1 j\mod2 = 1 jmod2=1 的两种情况。
那么,我们只需要用 j j j 来代替第二个维度,同时删去第三个维度即可。即定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个字符中,如果选 a i a_i ai 那么如果 j = 0 j = 0 j=0 ,说明它是第奇数个被选的;如果 j = 1 j = 1 j=1 ,说明它是第偶数个被选的。
那么,显然有以下递推式: d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + a [ i ] ∗ 2 ) dp[i][0] = max(dp[i-1][0],dp[i-1][1]+a[i]*2) dp[i][0]=max(dp[i−1][0],dp[i−1][1]+a[i]∗2) d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 0 ] + a [ i ] , d p [ i − 1 ] [ 1 ] ) dp[i][1] = max(dp[i-1][0]+a[i],dp[i-1][1]) dp[i][1]=max(dp[i−1][0]+a[i],dp[i−1][1])
需要注意的是,如果选 a i a_i ai ,那么 j j j 的取值需要变化(即0变1,1变0)。并且只有 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 时才可以考虑加上 a i ∗ 2 a_i*2 ai∗2。
这样一来,时间复杂度为 O ( n ) O(n) O(n) ,可以通过此题。
4.注意事项
- 需要开long long。
- 注意区分dp的状态转移方程。
- dp初始化: d p [ 1 ] [ 0 ] = 0 , d p [ 1 ] [ 1 ] = a [ 1 ] dp[1][0] = 0,dp[1][1] = a[1] dp[1][0]=0,dp[1][1]=a[1] 。
- dp计算答案: m a x ( d p [ n ] [ 0 ] , d p [ n ] [ 1 ] ) max(dp[n][0],dp[n][1]) max(dp[n][0],dp[n][1]) 。
- 由于dp数组开了long long,所以需要定义一个最大值函数。
5.代码实现 & 题目练习
请根据题解讲解补全代码(第4题5分,第5题3分,其余一题2分,共14分)
- 不允许在补全代码时参考以上题解,请独立完成,题解中有答案。
- 本试题难度约为CSP-J第一轮代码补全第2题。
#include <bits/stdc++.h>
using namespace std;
#define intt long long
intt n,a[200005];
intt dp[200005][2];
intt maxx(intt a,intt b)
{
if (__1__) return a;
return b;
}
int main()
{
cin >> n;
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
dp[1][0] = 0;
dp[1][1] = a[1];
for (int i=__2__;i<=n;i++)
{
dp[i][0] = maxx(dp[i-1][0],__3__);
dp[i][1] = __4__
}
cout<<__5__;
return 0;
}
- __1__处应填()
- A. a < b
- B. a > b
- C.a == b
- D.a == 0 || b == 0
- __2__处应填()
- A.0
- B.1
- C.2
- D.a[1]
- __3__处应填()
- A. dp[i-1][0]+a[i]
- B. dp[i-1][0]+a[i]*2
- C. dp[i-1][1]+a[i]
- D. dp[i-1][1]+a[i]*2
- __4__处应填()
- A. maxx(dp[i-1][0]+a[i],dp[i-1][0])
- B. maxx(dp[i-1][0]+a[i]*2,dp[i-1][1])
- C. maxx(dp[i-1][1]+a[i],dp[i-1][0])
- D. maxx(dp[i-1][1]+a[i]*2,dp[i-1][1])
- E. maxx(dp[i-1][1],dp[i-1][1]+a[i])
- F. maxx(dp[i-1][0]+a[i],dp[i-1][1])
- __5__处应填()
- A. maxx(dp[n][0],dp[n][1])
- B. maxx(dp[n-1][0],dp[n-1][1])
- C. maxx(dp[1][0],dp[1][1])
- D. dp[n][0]+dp[n][1]
6.本题小结
Atcoder Beginner Contest369 D题题解
主要用到的是dp优化的思路,当然也有别的优化方法,但是这种思路的时间复杂度显然是比较优的
O
(
n
)
O(n)
O(n) ,也可以尝试
O
(
n
log
n
)
O(n \log n)
O(nlogn) 解决。整体难度【普及/提高-】左右,可能在CSP-J第2.3题或CSP-S第1题。
附:参考答案
1.B 2.C 3.D 4.F 5.A