【贪心】 51nod 1115 最大M字段和 V3
思路:连续上升,连续下降的值放到set里面,然后对于大于m的集合双向链表进行合并,合并肯定是找绝对值最小的合并。
代码:
#include <cstdio> #include <cstring> #include <set> #include <algorithm> using namespace std; typedef long long ll; const int N = 2000005; ll s[N]; set<pair<ll, int> > a; int n, m, now; int pr[N], ne[N]; void Erase(int x) { int l = pr[x], r = ne[x]; ne[l] = r, pr[r] = l; } int main() { scanf("%d%d", &n, &m); ll tem = 0, ans = 0; int cnt = 0; for(int i = 1, x; i <= n; ++i) { scanf("%d", &x); if((tem < 0 && x > 0) || (tem > 0 && x < 0)) { now += tem > 0; s[++cnt] = tem; a.insert(make_pair(abs(tem), cnt)); tem = 0; } tem += x; ans += x > 0 ? x : 0; } if( ( tem >= 0 && s[1] > 0 ) || ( tem <= 0 && s[1] < 0 ) ) { a.erase(make_pair(abs(s[1]),1)); s[1] += tem; a.insert(make_pair(abs(s[1]),1)); } else { now += tem > 0; s[++cnt] = tem; a.insert( make_pair(abs( tem ), cnt ) ); } for( int i = 1; i <= cnt; ++i ) { pr[i] = i - 1, ne[i] = i + 1; } pr[1] = cnt, ne[cnt] = 1; for( ; now > m; --now ) { int x = ( *a.begin() ).second; a.erase( make_pair(abs(s[x] ), x ) ); a.erase( make_pair(abs(s[pr[x]] ), pr[x] ) ), a.erase(make_pair(abs( s[ne[x]] ), ne[x] ) ); ans -= abs( s[x] ); s[x] = s[x] + s[pr[x]] + s[ne[x]]; Erase( pr[x] ); Erase( ne[x] ); a.insert( make_pair(abs( s[x]), x ) ); } printf( "%I64d\n", ans ); return 0; }