NOI2010 超級鋼琴


題目大意:

       懶得寫了。。。。。。。

題解:

       要求前k小,顯然貪心。

       假定我們選取了一個左端點op那么右端點的選取范圍就固定在[op+L-1,op+R-1],那么我們可以維護一個三元組,即i與其選取范圍。但我們會在某個區間選取諸如次大值,次次大值,次次次。。。。。。次大值。那么我們之前的三元組就還需要一個新的元素,即選取位置t。當我們使用了這個四元組之后,區間就應該刪掉t,換一種思路,就是從t這個位置裂解成兩個區間,次大值一定在這兩個區間一種,這樣我們依靠一個堆,重復以上操作即可。而在最大值的區間選取,我們可以依靠一個ST表來實現

時間復雜度:$O(nlog_2(n)+klog_2^2(n))$

 1 #include<cstdio>
 2 #include<queue>
 3 void read(int &x){
 4     x=0;bool k=0;
 5     char ch=getchar();
 6     while(ch<'0'||ch>'9')  k=ch=='-'?1:k, ch=getchar();
 7     while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
 8     x=x*(k==1?-1:1);
 9 }
10 const int N=500500;
11 int n,k,L,R;
12 int a[N],sum[N];
13 inline int min(int a,int b){return a<b?a:b;}
14 struct node{int op,l,r,t;
15      friend bool operator <(node x,node y){
16          return sum[x.t]-sum[x.op-1]<sum[y.t]-sum[y.op-1];
17      }
18 };
19 long long ans;
20 int mx[20][N];
21 int lg[N],pow[20];
22 inline  void ST(){
23     lg[0]=-1;for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
24     pow[0]=1;for(int i=1;i<=19;i++) pow[i]=pow[i-1]<<1;
25     for(int i=1;i<=n;i++)   mx[0][i]=i;
26     for(int i=1;pow[i]<=n;i++)
27         for(int j=1;j<=n-pow[i]+1;j++){
28             int t=mx[i-1][j],t1=mx[i-1][j+pow[i-1]];
29             mx[i][j]=sum[t]>sum[t1]?t:t1;
30         }
31 }
32 inline int query(int l,int r){
33     int q=lg[r-l+1];
34      int t1=mx[q][l],t2=mx[q][r-pow[q]+1];
35     return sum[t1]>sum[t2]?t1:t2;
36 }
37 std::priority_queue<node> q;
38 inline void solve(){
39     for(int i=1;i<=n-L+1;i++)   {
40         int l=i+L-1,r=min(i+R-1,n);
41         int t=query(l,r);
42         q.push((node){i,l,r,t});
43     }
44     for(int i=1;i<=k;i++){
45         node now=q.top();q.pop();
46         ans+=sum[now.t]-sum[now.op-1];
47         if(now.t+1<=now.r)
48         q.push((node){now.op,now.t+1,now.r,query(now.t+1,now.r)});
49         if(now.t-1>=now.l)
50         q.push((node){now.op,now.l,now.t-1,query(now.l,now.t-1)});
51     }
52 }
53 int main(){
54     freopen("piano.in","r",stdin);
55     freopen("piano.out","w",stdout);
56     read(n),read(k),read(L),read(R);
57     for(int i=1;i<=n;i++) read(a[i]);
58     for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
59     ST();
60     solve();
61     printf("%lld",ans);
62 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM