給定乙個長為n的序列,從中選出k個不同的長度在[l,r]範圍內的區間,使得這些選出的數的和最大
區間求和,首先要求字首和sum
如果固定了左端點,那麼右端點就會在右邊一定範圍內移動,我們把固定的左端點設為p,右邊的範圍設為[l,r],以p為左端點的最大區間的右端點一定是在[l,r]範圍內的最大sum所在的位置,即求區間最大,由於不帶修改,所以所有的sum不會改變,求區間最大可以用st表完成,只是這裡的st表維護最大值所在的位置而不是值。再開乙個堆來維護(p,l,r)這樣的三元組的最大值即可
不能取重複區間。如果取了乙個區間[p,t],將[l,r]拆成[l,t-1],[t+1,r]重新分別和t插入堆中即可
code:
#include#include#include#include#define n 500005
using namespace std;
typedef long long ll;
int n,k,l,r;
ll a[n],sum[n];
int maxx[n][21],lg[n];
int getmax(int l,int r)
struct node
};priority_queueq;
template void read(t &x)
void init()
for(int i=1;i<=n;++i) lg[i]=log2(i);
}int main()
init();
for(int i=1;i<=n;++i) if(i+l-1<=n) q.push((node));
ll ans=0;
for(int i=1;i<=k;++i)
); if(u.r!=t) q.push((node));
} cout
}
NOI2010 超級鋼琴
傳送門 這個題有趣。巧妙地利用st表和堆 首先最暴力的我就不說了 第二個暴力就是主席樹 堆,預計得分70 80,時間o klog 2n std是用堆儲存可能的區間,然後用st表查詢區間最小值 因為其實如果知道區間右端點,再處理個字首和s 那麼就只要查詢區間最小值就可以了,可以st表o 1 做 inc...
NOI2010 超級鋼琴
求出字首和 對於每個結尾i,設現在取的區間是 j 1,i 則i r j i l,取出該區間sum j 的最小值,將sum i sum j 放入堆中 建立乙個大根堆,每次取出堆頂元素,將排名k 1,將sum i 區間第k小值放入堆中 求區間第k小可以用主席樹 直到取滿k次為止 include incl...
NOI2010 超級鋼琴
和有一道區間前k大異或很像。先求字首和,然後就變成右端點固定,取左端點的第k小問題,主席樹維護即可。並用堆維護前k個。ac pragma gcc optimize ofast funroll all loops include define int long long using namespace...