zoukankan      html  css  js  c++  java
  • 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
    ", 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
  • 相关阅读:
    求两图的 对比度
    关于opencv中的颜色模型转换之CV_BGR2HSV
    转 C++函数返回值,你必须注意的问题
    opencv 3.2 vs2015 debug assertion __acrt_first_block == header
    vs的【warning C4996:'fopen': This function or variable may be unsafe】解决方案
    c++ opencv 3.2 +Mfc VS2015窗体显示图片方法
    c++中“箭头(->)”和“点号(.)”操作符的区别
    C# devexpress gridcontrol 分页 控件制作
    c#Md5 32位加密结果少了两个0的原因
    opencv 线,椭圆 圆
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9788450.html
Copyright © 2011-2022 走看看