bzoj2288 生日禮物(貪心)(堆)(鍊錶)

2021-08-22 19:44:34 字數 1138 閱讀 1405

ftiasch 18歲生日的時候,lqp18_31給她看了乙個神奇的序列 a1, a2, …, an. 她被允許選擇不超過 m 個連續的部分作為自己的生日禮物。

自然地,ftiasch想要知道選擇元素之和的最大值。你能幫助她嗎?

相鄰的兩個數如果同為正數或負數可以合併成乙個大的正數或負數,這樣整個數列就成了正負交替的了。

當m=1時,最大子串行是答案。

我們考慮設定反悔機制。假設最大子串行的區間為[l,r],我們給[l,r]間的數取相反數,如果可以和旁邊的數合併則合併。如果選擇了反悔機制中的數,意思是取消剛剛的操作。

這個想法在複雜度上已經輸了,其正確性還有待證明……

堆+鍊錶+貪心

相鄰兩數同號合併的想法沒有錯,正解的難點在與逆向思維。

假設全部的正數都選了,ans=所有正數和。這是m>=正數集合的情況。

如果不是,我們就要進行部分捨棄,使新正數集合==m。

捨棄有兩種方式:

1、選擇乙個正數,ans-=a[i],表示不選這個正數集合。

2、選擇乙個負數,ans-=abs(a[i]),表示把負數兩邊正數連帶中間的負數一起選了。

因為不能連續,所以選了a[i]這個集合,a[l[i]]和a[r[i]]就不能選了。對於正數和負數的a[i]我們以絕對值的方式來評定它的價值,越小越優。

這樣問題就轉化成了bzoj1150。

#include#include#include#includeusing namespace std;

const int inf=(1ll<<31)-1;

const int maxl=1e5+10;

int n=0,n,m;

int a[maxl];

int l[maxl],r[maxl];

struct q

};priority_queueq;

void remove(int x)

int main()

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

);l[i]=i-1;r[i]=i+1;

}while(tot>m)

);remove(lx);remove(rx);}}

printf("%d\n",ans);

return 0;

}

BZOJ 2288 生日禮物

題目鏈結 演算法 先將這個序列的正負數合併起來,變成乙個正負交替的序列 如果新序列的正數個數小於等於m,那麼直接輸出正數的和即可 否則,我們可以將某些正數和負數合併起來,或者不要某些正數 將所有數按絕對值排序,放入堆中,問題就轉化為了 在這些數中選出 cnt m 個數 其中cnt為正數的個數 選了乙...

BZOJ2288 生日禮物 堆 鍊錶 貪心

顯然符號相同的一段會一起被選,因此先合併符號相同的各段,最終得到正數負數相間的序列。設此時有 cnt cntcn t 個正數,且其和為 sum sumsu m,若 cnt m cnt leq m cnt m,則答案為 sum sumsu m。否則,每次找出絕對值最小的數,將其與序列中相鄰兩數合併,直...

BZOJ 1293 生日禮物

我發現bzoj的水題都比較高檔昂。這道題的基本思想是,每次用優先佇列把位置最靠前的顏色彈出來,並把與它顏色相同的下乙個點的位置進佇列,每次更新最優長度。1.初始化 每個點的下乙個相同顏色點的位置。2.將每個顏色的第乙個點入佇列,算第乙個狀態。3.每次將佇列最前端的顏色彈出,將他的下乙個點放入佇列,更...