51Nod 1053 最大M子段和 V2

2021-08-07 19:49:58 字數 1875 閱讀 7276

acm模版

這個題需要用到貪心搞。

首先涉及到一點優化是,連續的正數或者連續的負數,到最後肯定是可以合併在一起的,所以我們首先將序列中的相鄰正數或者相鄰負數全部合併,將序列壓縮,也許這個也談不上什麼優化,因為這個步驟對於整個貪心過程是必須的,在這個過程中,累計下來所有正數的和。

此時,我們可以發現,新的序列是乙個一正一負交替的序列,貌似叫做擺動序列吧,那麼此時我們可以考慮合併(如果需要的話),合併時我們需要貪心,每次先找最小的(絕對值),如果最小的是負數,我們就加入它,相當於將它前後的數鏈結在了一起,成為了乙個區間,反之,我們就需要刪除它,相當於捨去了乙個正數區間。這裡不難理解,每次我們都需要對最小代價進行修改,因為如果只考慮正數或者負數,那麼顯然會因為新增了絕對值過大的負數而使結果不能最優,也會存在因為刪除了過大的正數而比新增乙個小的負數產生的損失更大。

至於這裡的合併過程,我們可以用鍊錶優化,自己實現乙個**的鍊錶,挺簡單的,合併的過程中,將左右的值新增到中間,然後刪除左右兩邊即可,另外用 se

t 或者優先佇列維護最小代價應該是不錯的,剩下的就沒有什麼了。

#include 

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

const

int maxn = 2e6 + 10;

template

inline

bool scan_d(t &ret)

while (c != '-' && (c < '0' || c > '9'))

sgn = (c == '-') ? -1 : 1;

ret = (c == '-') ? 0 : (c - '0');

while (c = getchar(), c >= '0' && c <= '9')

ret *= sgn;

return1;}

ll a[maxn];

int n, m, now;

int pre[maxn];

int net[maxn];

setint> > a;

void _erase(int x)

if (r)

}int main()

tmp += x;

ans += x > 0 ? x : 0;

}now += tmp > 0;

a[++cnt] = tmp;

a.insert(make_pair(abs(tmp), cnt));

// 構造鍊錶結構

for (int i = 1; i <= cnt; ++i)

net[cnt] = a[0] = 0;

while (now > m)

a.erase(make_pair(abs(a[pre[x]]), pre[x]));

a.erase(make_pair(abs(a[net[x]]), net[x]));

ans -= abs(a[x]);

a[x] = a[x] + a[pre[x]] + a[net[x]];

_erase(pre[x]);

_erase(net[x]);

a.insert(make_pair(abs(a[x]), x));

now--;

}printf("%lld\n", ans);

return

0;}

51NOD 1053 最大M子段和 V2 題解

n個整數組成的序列a1 1 a2 2 a3 3 an n,將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。wqs二分 帶權二分裸題,顯然函式為凸函式...

51Nod 1052 最大M子段和

n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。刷刷水有益身心健康。不過我還是沒有一眼看出來。考慮...

51Nod1052 最大M子段和

n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。input 第1行 2個數n和m,中間用空格分隔。...