【題目鏈結】
【演算法】
先將這個序列的正負數合併起來,變成乙個正負交替的序列
如果新序列的正數個數小於等於m,那麼直接輸出正數的和即可
否則,我們可以將某些正數和負數合併起來,或者不要某些正數
將所有數按絕對值排序,放入堆中,問題就轉化為了 : 在這些數中選出(cnt - m)個數(其中cnt為正數的個數),
選了乙個數後相鄰的兩個數就不能選,使得最後的和盡可能小
這個問題可以用ctsc2007資料備份的方法來解決,詳見 :
【**】
#includeusingnamespace
std;
const
int maxn = 1e5 + 10
;const
int inf =2e9;
struct
info
;int
i,n,m,l,r,cnt,ans,len;
inta[maxn],b[maxn],val[maxn],pre[maxn],nxt[maxn];
bool
visited[maxn];
info tmp;
class
heap
inline
void up(int
x)
}inline
void down(int
x)
}inline
void
insert(info x)
inline
void
del()
inline info
get()
} h;
intmain()
for (; i <= n; i++)
for (i = 1; i <= len; i++)
else b[i] = -b[i];
}if (cnt <=m)
for (i = 1; i <= len; i++));}
b[0] = b[len+1] =inf;
for (i = m; i < cnt; i++)
ans -=tmp.d;
h.del();
visited[pre[tmp.pos]] = true
; visited[nxt[tmp.pos]] = true
; b[tmp.pos] = b[pre[tmp.pos]] + b[nxt[tmp.pos]] -tmp.d;
nxt[pre[pre[tmp.pos]]] =tmp.pos;
pre[tmp.pos] =pre[pre[tmp.pos]];
pre[nxt[nxt[tmp.pos]]] =tmp.pos;
nxt[tmp.pos] =nxt[nxt[tmp.pos]];
h.insert((info));
}
printf(
"%d\n
",ans);
return0;
}
bzoj2288 生日禮物(貪心)(堆)(鍊錶)
ftiasch 18歲生日的時候,lqp18 31給她看了乙個神奇的序列 a1,a2,an.她被允許選擇不超過 m 個連續的部分作為自己的生日禮物。自然地,ftiasch想要知道選擇元素之和的最大值。你能幫助她嗎?相鄰的兩個數如果同為正數或負數可以合併成乙個大的正數或負數,這樣整個數列就成了正負交替...
BZOJ2288 生日禮物 堆 鍊錶 貪心
顯然符號相同的一段會一起被選,因此先合併符號相同的各段,最終得到正數負數相間的序列。設此時有 cnt cntcn t 個正數,且其和為 sum sumsu m,若 cnt m cnt leq m cnt m,則答案為 sum sumsu m。否則,每次找出絕對值最小的數,將其與序列中相鄰兩數合併,直...
BZOJ 1293 生日禮物
我發現bzoj的水題都比較高檔昂。這道題的基本思想是,每次用優先佇列把位置最靠前的顏色彈出來,並把與它顏色相同的下乙個點的位置進佇列,每次更新最優長度。1.初始化 每個點的下乙個相同顏色點的位置。2.將每個顏色的第乙個點入佇列,算第乙個狀態。3.每次將佇列最前端的顏色彈出,將他的下乙個點放入佇列,更...