顯然符號相同的一段會一起被選,因此先合併符號相同的各段,最終得到正數負數相間的序列。
設此時有 cnt
cntcn
t 個正數,且其和為 sum
sumsu
m,若 cnt
≤m
cnt \leq m
cnt≤
m,則答案為 sum
sumsu
m。否則,每次找出絕對值最小的數,將其與序列中相鄰兩數合併,直至 cnt
=m
cnt = m
cnt=m。
若找出的數是負數,則相當於以最小的代價將兩段正數連線;
若找出的數是正數,則相當於捨棄該正數,以消除負數的影響。
每次操作均會使 cnt
=cnt
−1
cnt = cnt - 1
cnt=cn
t−1,sum
=sum
−∣a[
i]
∣sum = sum - |a[i]|
sum=su
m−∣a
[i]∣
,a [i
]a[i]
a[i]
為選出的值。
這也可以解釋為什麼每次取出絕對值最小的數。
可以用堆和鍊錶來實現,若取出的是負數且處於鍊錶邊界,則直接捨棄即可。
#include
#include
#include
#include
using
namespace std;
inline
intread()
while
(c >=
'0'&& c <=
'9')
num = num *
10+ c -
'0', c =
getchar()
;return flag * num;
}const
int maxn =
1e5+5;
struct node1 };
struct node2 list[maxn]
;struct heap
voidup(
int p)
else
break;}
}void
down
(int p)
else
break;}
}void
push
(node1 x)
void
pop(
int p =1)
} heap;
inline
void
del(
int x)
int a[maxn]
, tot;
intmain()
for(
int i =
1; i <= tot;
++i)
if(cnt <= m)
while
(cnt > m)
else
if(y.r == tot +1)
else
x.v = y.v;
heap.
push
(x);
}printf
("%d"
, sum)
;return0;
}
bzoj2288 生日禮物(貪心)(堆)(鍊錶)
ftiasch 18歲生日的時候,lqp18 31給她看了乙個神奇的序列 a1,a2,an.她被允許選擇不超過 m 個連續的部分作為自己的生日禮物。自然地,ftiasch想要知道選擇元素之和的最大值。你能幫助她嗎?相鄰的兩個數如果同為正數或負數可以合併成乙個大的正數或負數,這樣整個數列就成了正負交替...
BZOJ 2288 生日禮物
題目鏈結 演算法 先將這個序列的正負數合併起來,變成乙個正負交替的序列 如果新序列的正數個數小於等於m,那麼直接輸出正數的和即可 否則,我們可以將某些正數和負數合併起來,或者不要某些正數 將所有數按絕對值排序,放入堆中,問題就轉化為了 在這些數中選出 cnt m 個數 其中cnt為正數的個數 選了乙...
BZOJ 1293 生日禮物
我發現bzoj的水題都比較高檔昂。這道題的基本思想是,每次用優先佇列把位置最靠前的顏色彈出來,並把與它顏色相同的下乙個點的位置進佇列,每次更新最優長度。1.初始化 每個點的下乙個相同顏色點的位置。2.將每個顏色的第乙個點入佇列,算第乙個狀態。3.每次將佇列最前端的顏色彈出,將他的下乙個點放入佇列,更...