NOI2010 超级钢琴
2017-07-25 11:21
169 查看
[b]题目大意:[/b]
懒得写了。。。。。。。
假定我们选取了一个左端点op那么右端点的选取范围就固定在[op+L-1,op+R-1],那么我们可以维护一个三元组,即i与其选取范围。但我们会在某个区间选取诸如次大值,次次大值,次次次。。。。。。次大值。那么我们之前的三元组就还需要一个新的元素,即选取位置t。当我们使用了这个四元组之后,区间就应该删掉t,换一种思路,就是从t这个位置裂解成两个区间,次大值一定在这两个区间一种,这样我们依靠一个堆,重复以上操作即可。而在最大值的区间选取,我们可以依靠一个ST表来实现
时间复杂度:$O(nlog_2(n)+klog_2^2(n))$
懒得写了。。。。。。。
[b]题解:[/b]
要求前k小,显然贪心。假定我们选取了一个左端点op那么右端点的选取范围就固定在[op+L-1,op+R-1],那么我们可以维护一个三元组,即i与其选取范围。但我们会在某个区间选取诸如次大值,次次大值,次次次。。。。。。次大值。那么我们之前的三元组就还需要一个新的元素,即选取位置t。当我们使用了这个四元组之后,区间就应该删掉t,换一种思路,就是从t这个位置裂解成两个区间,次大值一定在这两个区间一种,这样我们依靠一个堆,重复以上操作即可。而在最大值的区间选取,我们可以依靠一个ST表来实现
时间复杂度:$O(nlog_2(n)+klog_2^2(n))$
#include<cstdio> #include<queue> void read(int &x){ x=0;bool k=0; char ch=getchar(); while(ch<'0'||ch>'9') k=ch=='-'?1:k, ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); x=x*(k==1?-1:1); } const int N=500500; int n,k,L,R; int a ,sum ; inline int min(int a,int b){return a<b?a:b;} struct node{int op,l,r,t; friend bool operator <(node x,node y){ return sum[x.t]-sum[x.op-1]<sum[y.t]-sum[y.op-1]; } }; long long ans; int mx[20] ; int lg ,pow[20]; inline void ST(){ lg[0]=-1;for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1; pow[0]=1;for(int i=1;i<=19;i++) pow[i]=pow[i-1]<<1; for(int i=1;i<=n;i++) mx[0][i]=i; for(int i=1;pow[i]<=n;i++) for(int j=1;j<=n-pow[i]+1;j++){ int t=mx[i-1][j],t1=mx[i-1][j+pow[i-1]]; mx[i][j]=sum[t]>sum[t1]?t:t1; } } inline int query(int l,int r){ int q=lg[r-l+1]; int t1=mx[q][l],t2=mx[q][r-pow[q]+1]; return sum[t1]>sum[t2]?t1:t2; } std::priority_queue<node> q; inline void solve(){ for(int i=1;i<=n-L+1;i++) { int l=i+L-1,r=min(i+R-1,n); int t=query(l,r); q.push((node){i,l,r,t}); } for(int i=1;i<=k;i++){ node now=q.top();q.pop(); ans+=sum[now.t]-sum[now.op-1]; if(now.t+1<=now.r) q.push((node){now.op,now.t+1,now.r,query(now.t+1,now.r)}); if(now.t-1>=now.l) q.push((node){now.op,now.l,now.t-1,query(now.l,now.t-1)}); } } int main(){ freopen("piano.in","r",stdin); freopen("piano.out","w",stdout); read(n),read(k),read(L),read(R); for(int i=1;i<=n;i++) read(a[i]); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]; ST(); solve(); printf("%lld",ans); }
相关文章推荐
- bzoj 2006 [NOI2010]超级钢琴 二分答案 可持久化线段树
- [BZOJ2006][NOI2010]超级钢琴(st表+堆贪心)
- NOI2010 超级钢琴
- bzoj2006 [NOI2010]超级钢琴
- [BZOJ2006][NOI2010]超级钢琴
- [NOI2010][bzoj2006] 超级钢琴 [主席树/ST表+堆]
- P2048 [NOI2010]超级钢琴
- bzoj 2006: [NOI2010]超级钢琴
- BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]
- [BZOJ2006] [NOI2010]超级钢琴
- 【贪心】BZOJ2006 [NOI2010]超级钢琴
- 【BZOJ 2006】 [NOI2010]超级钢琴
- [NOI2010]超级钢琴(堆)
- bzoj2006 [NOI2010]超级钢琴
- [NOI 2010]超级钢琴
- 2006: [NOI2010]超级钢琴
- BZOJ2006 [NOI2010]超级钢琴 【堆 + RMQ】
- BZOJ2006: [NOI2010]超级钢琴(洛谷P2048)
- bzoj 2006: [NOI2010]超级钢琴 可持久化线段树+优先队列
- NOI2010 : 超级钢琴