zoukankan      html  css  js  c++  java
  • luogu P1121 环状最大两段子段和

    嘟嘟嘟

    一道说难也难说简单也简单的dp题。

    我觉得我的(有篇题解)做法就属于特别简单的。

    平时遇到环的问题都是断环为链,但这道题给了一种新的思路。

    观察一下,最后的答案无非就这两种:xxx--xx---xxxx

                       ----xxx-----xx---

    对于第二种,有一个特别好的做法:正着求一遍最大子串和,再倒着求一遍,然后枚举断点拼接起来。

    至于第一种情况,只要很巧妙的转化一下,就变成了第二种:正反两遍求最小子串和,然后拿总和减一下就成了。至于最小子串和,可以取相反数,就变成了求最大子串和。

    所以这道题就做完了。

    但是如果序列中只有一个正数的话,就不能再求第一种情况,比如-3 -2 4 -5 -6,按上述算法求出来的是0,。所以特判掉就好。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e5 + 5;
    21 inline ll read()
    22 {
    23   ll ans = 0;
    24   char ch = getchar(), last = ' ';
    25   while(!isdigit(ch)) {last = ch; ch = getchar();}
    26   while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27   if(last == '-') ans = -ans;
    28   return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32   if(x < 0) x = -x, putchar('-');
    33   if(x >= 10) write(x / 10);
    34   putchar(x % 10 + '0');
    35 }
    36 
    37 int n, sum = 0, a[maxn];
    38 
    39 int f[maxn], g[maxn];
    40 int query()
    41 {
    42   Mem(f, -0x3f); Mem(g, -0x3f);
    43   for(int i = 1; i <= n; ++i) f[i] = max(f[i - 1], 0) + a[i];
    44   for(int i = n; i; --i) g[i] = max(g[i + 1], 0) + a[i];
    45   for(int i = 1; i <= n; ++i) f[i] = max(f[i], f[i - 1]);
    46   for(int i = n; i; --i) g[i] = max(g[i], g[i + 1]);
    47   int ret = -INF;
    48   for(int i = 1; i < n; ++i) ret = max(ret, f[i] + g[i + 1]);
    49   return ret;
    50 }
    51 
    52 int main()
    53 {
    54   n = read();
    55   int tot = 0;
    56   for(int i = 1; i <= n; ++i) a[i] = read(), sum += a[i], tot += a[i] > 0;
    57   int ans1 = query();
    58   if(tot == 1) {write(ans1), enter; return 0;}
    59   for(int i = 1; i <= n; ++i) a[i] = -a[i];
    60   int ans2 = sum + query();
    61   if(!ans2) ans2 = -INF;
    62   write(max(ans1, ans2)), enter;
    63   return 0;
    64 }
    View Code

     至于难得做法吗,无非就是特别复杂的dp转移方程,有兴趣的可以看别的题解~

  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/mrclr/p/9853115.html
Copyright © 2011-2022 走看看