BZOJ2006:[NOI2010]超級鋼琴
阿新 • • 發佈:2018-12-17
lse ace pos arr urn read printf nod getc 。假設最優左端點是\(pos'\),那麽對於最優解,我們只需要執行如下步驟\(k\)次即可:
我對\(RMQ\)的理解:https://www.cnblogs.com/AKMer/p/10128219.html
題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=2006
首先,序列\([l,r]\)的和可以轉化成前綴和相減:\(sum[r]-sum[l-1]\)。
其次,對於每個右端點\(pos\),有效左端點都是一段區間\([pos-r,pos-l]\)。而這裏面前綴和最小的則是最優左端點。
一開始我們將所有的四元組\((v,pos,l,r)\)丟到大根堆裏。這個四元組表示以\(pos\)為右端點,有效左端點區間在\([l,r]\)內,最大值為\(v\)
取出堆頂,\(ans+=v\)。
將\((sum[pos]-query(l,pos'-1),pos,l,pos'-1)\)與\((sum[pos]-query(pos'+1,r),pos,pos'+1,r)\)放回堆裏。這樣可以保證\([pos',pos]\)不會再被取出。
\(query(l,r)\)表示求區間\([l,r]\)的前綴和最小值。這樣,問題就得到了完美解決。
時間復雜度:\(O(nlogn)\)
空間復雜度:\(O(nlogn)\)
代碼如下:
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int maxn=5e5+5; ll ans; int n,limit,L,R; int a[maxn],Log[maxn],f[20][maxn]; int read() { int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; return x*f; } struct node { int v,pos,l,r; node() {} node(int _v,int _pos,int _l,int _r) { v=_v,pos=_pos,l=_l,r=_r; } bool operator<(const node &a)const { return v<a.v; } }; struct Heap { int tot; node tree[maxn<<1]; void ins(node a) { tree[++tot]=a; int pos=tot; while(pos>1) { if(tree[pos>>1]<tree[pos]) swap(tree[pos>>1],tree[pos]),pos>>=1; else break; } } node pop() { node res=tree[1]; tree[1]=tree[tot--]; int pos=1,son=2; while(son<=tot) { if(son<tot&&tree[son]<tree[son|1])son|=1; if(tree[pos]<tree[son]) swap(tree[pos],tree[son]),pos=son,son=pos<<1; else break; } return res; } }T;//手寫堆carry你進第一版,值得擁有! int fake(int num1,int num2) { if(a[num1]<a[num2])return num1; return num2; } int query(int l,int r) { int x=Log[r-l+1]; return fake(f[x][l],f[x][r-(1<<x)+1]); } int main() { n=read(),limit=read(); L=read(),R=read();Log[0]=-1; for(int i=1;i<=n;i++) { f[0][i]=i; Log[i]=Log[i>>1]+1; a[i]=read()+a[i-1]; } for(int i=1;i<=19;i++) for(int j=0;j+(1<<i)-1<=n;j++) f[i][j]=fake(f[i-1][j],f[i-1][j+(1<<(i-1))]); for(int i=L;i<=n;i++) { int l=max(0,i-R),r=i-L; T.ins(node(a[i]-a[query(l,r)],i,l,r)); } for(int i=1;i<=limit;i++) { node tmp=T.pop(); ans+=tmp.v; int pos=query(tmp.l,tmp.r); if(pos-1>=tmp.l) T.ins(node(a[tmp.pos]-a[query(tmp.l,pos-1)],tmp.pos,tmp.l,pos-1)); if(pos+1<=tmp.r) T.ins(node(a[tmp.pos]-a[query(pos+1,tmp.r)],tmp.pos,pos+1,tmp.r)); } printf("%lld\n",ans); return 0; }
BZOJ2006:[NOI2010]超級鋼琴