P2048 [NOI2010]超级钢琴
无关:突然感觉之前的码风调代码不太方便,还是稍微改一下吧,毕竟现在竞赛的代码写出来还是要给自己看的...
这道题,显然确定了一个端点之后这个端点对应的区间和的最大值是定的,很容易想到用ST表维护一个前缀和最大值
然后再维护一个大根堆,记录每个合法最大值区间
在每一个状态时,堆顶元素一定是最优解,所以每次取堆顶元素即可
但是把堆顶元素取出来之后,之后最优解还有可能在当前堆顶的集合中的子集里产生,所以还需要把当前堆顶有可能产生的其他贡献丢到堆里
设堆顶元素在位置pos处取到最优解的情况,那么因为两个和弦不能相同,可能的新的贡献的右端点只有可能在$[l,pos-1]$和$[pos+1,r]$中取到
把这两个区间也丢进去维护就好了
1 //hgs AK IOI,IMO,ICHO,IPHO 2 #include<bits/stdc++.h> 3 #define int long long 4 #define writeln(x) write(x),puts("") 5 #define writep(x) write(x),putchar(' ') 6 using namespace std; 7 inline int read(){ 8 int ans=0,f=1;char chr=getchar(); 9 while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} 10 while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 11 return ans*f; 12 }void write(int x){ 13 if(x<0) putchar('-'),x=-x; 14 if(x>9) write(x/10); 15 putchar(x%10+'0'); 16 }const int M = 5E5+5; 17 int a[M],s[M],st[M][21],n,m,sl,sr,lg2[M]={-1},bin[21]={1}; 18 inline int max(int x,int y){return ((x>y)?(x):(y));} 19 inline int min(int x,int y){return ((x>y)?(y):(x));} 20 inline int chkmax(int x,int y){return (s[x]>s[y])?(x):(y);} 21 inline void Pre() 22 { 23 for(int i=1;i<=20;i++) 24 bin[i]=bin[i-1]<<1; 25 for(int i=1;i<=n;i++) 26 lg2[i]=lg2[i>>1]+1, 27 st[i][0]=i; 28 for(int j=1;j<=20;j++) 29 for(int i=1;i+bin[j]-1<=n;i++) 30 st[i][j]=chkmax(st[i][j-1],st[i+bin[j-1]][j-1]); 31 } 32 inline int Query(int l,int r) 33 { 34 return chkmax(st[l][lg2[r-l+1]],st[r-bin[lg2[r-l+1]]+1][lg2[r-l+1]]); 35 } 36 struct P 37 { 38 int x,l,r; 39 inline int Calc()const 40 { 41 return s[Query(l,r)]-s[x-1]; 42 } 43 friend bool operator<(const P&a,const P&b) 44 { 45 return a.Calc()<b.Calc(); 46 } 47 }; 48 priority_queue<P>q; 49 inline P Make(int x,int l,int r) 50 { 51 r=min(r,n); 52 return (P){x,l,r}; 53 } 54 inline void Split(const P&x) 55 { 56 P t1,t2; 57 int pos=Query(x.l,x.r); 58 if(x.l!=pos)q.push(Make(x.x,x.l,pos-1)); 59 if(x.r!=pos)q.push(Make(x.x,pos+1,x.r)); 60 } 61 signed main() 62 { 63 n=read(),m=read(),sl=read(),sr=read(); 64 for(int i=1,x;i<=n;i++) 65 s[i]=read(),s[i]+=s[i-1]; 66 Pre(); 67 for(int i=1;i+sl-1<=n;i++) 68 q.push(Make(i,i+sl-1,i+sr-1)); 69 register int ans(0); 70 while(m--) 71 { 72 P now=q.top(); 73 q.pop(); 74 ans+=now.Calc(); 75 Split(now); 76 }cout<<ans; 77 return 0; 78 }