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 }