有乙個包含 n 個正整數的序列,序列元素不大於 n。緊接著,他們維護了一
個可重集合 s,包含序列中的前 p 個元素。alice 先手,二人輪流進行下面的一
系列操作:
從集合 s 中拿走乙個元素,加到玩家的總分上面;
將序列中的下乙個數字(如果存在)新增到集合 s 中;
假使二人都盡力使自己的總分最大,設遊戲的結果為 alice 的總分與 bob 的
總分之差,那麼請你在給定序列和集合元素的情況下,輸出遊戲的結果
n<=100000,q<=2000
為了簡單,我們可以看做本來只有p-1個元素,然後是先插入,再取出
比較顯然的性質是,每次都是取的multiset中最大那個元素
於是我們就直接上個multiset或者優先佇列,成功得到再nlogn的時間內搞定每次詢問
那麼現在的問題是怎麼優化呢
我們必須優化到o(n)內完成每次查詢
必須發現的一點是,每次我們只會往這個multiset中插乙個值,而且如果這個值大於了當前的最大值,就一定會被馬上取走
那麼也就是說,這個最大值一定是不增的
那麼如果當前增加值是大於這個最大值,就一定給當前的人加上這麼多分
那如果不是呢?我們會取出最大值,然後插入當前的這個值。
那麼問題來了怎麼實現呢?
二分鍊錶?或者乾脆直接上個二叉堆?似乎那個log怎麼都砍不掉啊?
然而…考慮到所有數都小於等於n,我們可以直接用乙個陣列來維護出現次數…成功實現o(1)插入,然後更新最大值暴力更新即可,由於是單調不增的,可以證明是o(n)的
於是最後o(nq)解決本題
記得開ll
#include
#include
#include
#include
using
namespace std;
typedef
long
long ll;
const
int n=
100005
;int n,m;
int a[n]
,cnt[n]
;int
main()
ll ans=0;
for(
int j=
1,k=
1;j<=n;j++
,k*=-1
)}else
}printf
("%lld\n"
,ans);}
}