51nod1254 最大子段和 V2 DP

~~~题面~~~

题解:

  表示今天做题一点都不顺。。。。

  这题也是看了题解思路然后自己想转移的。

  看的题解其实不是这道题,但是是这道题的加强版,因为那道题允许交换k对数。

  因为我们选出的是连续的一段,所以假设我们选了某一段,那么原序列将会被分为3段,我们设这3段分别是第0段,第1段和第2段,我们假设我们选出的区间是第1段。

  那么我们的目的就是要从第0段或第2段中选出一个数,从第1段中剔除一个数,使得1段中剩余数+选出数之和最大。  

  所以我们设f[i][j][k][l]表示DP到i位,已经选出了j个数,剔除了k个数, 当前在第l段的最大值。

  那么每次转移的时候就枚举一下当前的状态,如果当前在第0段or第2段,那么就考虑选出一个数or不选一个数。

  如果当前在第1段,那么就考虑剔除这个数or保留这个数。

  最后的答案就枚举一下最后一个数是属于哪一段,是否有交换(如果交换就是选出1个数,剔除1个数)。

  这里虽然强制交换,但和可以选择交换不交换是等效的。

  因为当n <= 2的时候,交换显然无意义。当n > 2的时候,属于1段的数的个数和不属于1段的数的个数中肯定有一个>= 2,那么交换一个段内部的数肯定是不会产生影响的,所以和不交换一样。

  因此选择不交换一定是合法的。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 50100
 5 #define LL long long
 6 
 7 int n;
 8 int s[AC];
 9 LL f[AC][2][2][3];//DP到i位, 选出j个,剔除k个,当前在第l段的最大值。
10 
11 inline int read()
12 {
13     int x = 0;char c = getchar();bool z = false;
14     while(c > '9' || c < '0') 
15     {
16         if(c == '-') z = true;
17         c = getchar();
18     }
19     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
20     if(!z) return x; 
21     else return -x;
22 }
23 
24 void pre()
25 {
26     n = read();
27     for(R i = 1; i <= n; i ++) s[i] = read();
28 }
29 
30 LL Max(LL a, LL b, LL c)
31 {
32     if(a > b && a > c) return a;
33     else if(b > c) return b;
34     else return c;
35 }
36 
37 LL Max_(LL a, LL b, LL c, LL d)
38 {
39     if(a > b && a > c && a > d) return a;
40     else if(b > c && b > d) return b;
41     else if(c > d) return c;
42     else return d;
43 }
44 
45 void work()
46 {
47     for(R i = 1; i <= n; i ++)
48     {
49          f[i][1][0][0] = max(f[i - 1][1][0][0], f[i - 1][0][0][0] + s[i]);
50          f[i][1][0][1] = max(f[i - 1][1][0][1], f[i - 1][1][0][0]) + s[i];
51          f[i][1][1][1] = Max(f[i - 1][1][0][0], f[i - 1][1][1][1] + s[i], f[i - 1][1][0][1]);
52          f[i][0][0][1] = max(f[i - 1][0][0][0], f[i - 1][0][0][1]) + s[i];
53          f[i][0][1][1] = Max(f[i - 1][0][1][1] + s[i], f[i - 1][0][0][0], f[i - 1][0][0][1]);
54          f[i][0][0][2] = max(f[i - 1][0][0][1], f[i - 1][0][0][2]);
55          f[i][1][1][2] = Max_(f[i - 1][1][1][2], f[i - 1][1][1][1], f[i - 1][0][1][2] + s[i], f[i - 1][0][1][1] + s[i]);
56          f[i][0][1][2] = max(f[i - 1][0][1][2], f[i - 1][0][1][1]);
57     }
58     printf("%lld\n", Max_(f[n][1][1][2], f[n][1][1][1], f[n][0][0][2], f[n][0][0][1]));
59 }
60 
61 int main()
62 {
63     freopen("in.in", "r", stdin);
64     pre();
65     work();
66     fclose(stdin);
67     return 0;
68 }
View Code

 

posted @ 2018-10-14 22:28  ww3113306  阅读(291)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。