码迷,mamicode.com
首页 > 其他好文 > 详细

51nod 1052 最大M子段和 & 1053 最大M子段和 V2

时间:2020-02-01 19:30:40      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:abs   --   ast   ++   最大m子段和   维护   spl   lap   max   


1052 dp即可
$dp[i][j]$ 表示前 $i$ 个数分成 $j$ 段。
$dp[i][j]=a[i]+\max\{dp[i-1][j], \max\{dp[k][j-1]\}\}$
前缀max优化一下即可

技术图片
#include <bits/stdc++.h>
#define ll long long

const int N = 5100;
ll dp[N][2];
int a[N], n, m;

inline ll max(ll a, ll b) {
    return a > b ? a : b;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", a + i);
    if (m >= n) {
        ll ans = 0;
        for (int i = 1; i <= n; i++)
            ans += a[i];
        printf("%lld\n", ans);
        return 0;
    }
    ll ans = 0;
    for (int j = 1; j <= m; j++) {
        ll mx = 0;
        int cur = j & 1, last = cur ^ 1;
        for (int i = 1; i <= n; i++) {
            dp[i][cur] = max(dp[i - 1][cur], mx) + a[i];
            mx = max(dp[i][last], mx);
            ans = max(ans, dp[i][cur]);
        }
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

 

1053 考虑把连续负数和连续正数缩成一段,先把所有正数取了,然后从绝对值小到大考虑每一段,如果是一段负数,就把它加入,相当于他和左右两端缩在一起,如果是一段正数,就把它删去。用set维护。

技术图片
#include <bits/stdc++.h>
#define ll long long
#define pii pair<ll, int>

const int N = 5e4 + 7;
ll a[N];
int pre[N], nxt[N], n, m;

std::set<std::pii> st;

void merge(int x) {
  int l = pre[x], r = nxt[x];
  if (l) nxt[l] = r;
  if (r) pre[r] = l;
}

int main() {
  scanf("%d%d", &n, &m);
  ll ans = 0, sum = 0;
  int cnt = 0, tol = 0;
  for (int i = 1; i <= n; i++) {
    int x;
    scanf("%d", &x);
    if ((sum < 0 && x > 0) || (sum > 0 && x < 0)) {
      a[++cnt] = sum;
      tol += sum > 0;
      st.insert(std::pii(std::abs(sum), cnt));
      sum = 0;
    }
    sum += x;
    if (x > 0) ans += x;
  }
  a[++cnt] = sum;
  tol += sum > 0;
  st.insert(std::pii(std::abs(sum), cnt));
  for (int i = 1; i <= cnt; i++) {
    pre[i] = i - 1;
    nxt[i] = i + 1;
  }
  nxt[cnt] = a[0] = 0;
  while (tol > m) {
    int x = (*st.begin()).second; st.erase(st.begin());
    if ((a[x] < 0 && (!pre[x] || !nxt[x])) || !a[x]) continue;
    if (pre[x]) st.erase(std::pii(std::abs(a[pre[x]]), pre[x]));
    if (nxt[x]) st.erase(std::pii(std::abs(a[nxt[x]]), nxt[x]));
    ans -= std::abs(a[x]);
    a[x] += a[pre[x]] + a[nxt[x]];
    st.insert(std::pii(std::abs(a[x]), x));
    merge(pre[x]);
    merge(nxt[x]);
    tol--;
  }
  printf("%lld\n", ans);
  return 0;
}
View Code

 

51nod 1052 最大M子段和 & 1053 最大M子段和 V2

标签:abs   --   ast   ++   最大m子段和   维护   spl   lap   max   

原文地址:https://www.cnblogs.com/Mrzdtz220/p/12249292.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!