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.每次將佇列最前端的顏色彈出,將他的下乙個點放入佇列,更...