[BZOJ 2006] [NOI 2010]スーパーピアノ(表貪欲+ ST +スタック)

[BZOJ 2006] [NOI 2010]スーパーピアノ(表貪欲+ ST +スタック)

フェイス質問

長さnの配列が与えられると、kが内側部分のセクションの値と全ての要素に等しく、k値及び最大間隔ように、LとRの間の間隔の長さから選択されます。節が交差または含まれていますが、範囲は一度だけ選択することができます。

\(N、K、L、Rの\当量5 \回10 ^ 5 \)

分析

第一セクションとプレフィックスに変換する。列挙エンドポイントを左(私は\)\、範囲の右端である\([+ L-I 1、\分(I-R&LTの+。1、N-)] \) これで内部プレフィクスと最大位置pの範囲を見つけ、答えは\(SUMは[P-] -sum [I-1] \) 静的メンテナンス間隔が最大位置STテーブルを用いて行うことができます。

しかし、我々は唯一の各点は回答のうち、左の最大値に対応する見つけることが、最大の間隔をk個頼む、Kではないかもしれません。暴力の各点は、すべてのセクションを列挙左ため、値のすべてがヒープに加え、そして最終的にタイムアウトになり、明らかにKを除去します。

我々は、スタックを維持する(STLはプライオリティキューに実装さ)、各要素内部スタックは三重である(\(I、L、R&LT))\インターバルを表す。左点\を(私は\) 右端点中([L、R] \) \ 時間内最大レッツ取ることができる\(F_M(L、R) \) の\([L、R] \ ) 次に、我々は、以下の最大の位置を(\を和[F_M(L、R) ] -和[I] \) 最大ヒープを維持します。最初の\((iは、iがL + -1、minは(iはR-1、n)を)+ \) ヒープ内に挿入されます。スタックの各撮影上部\((I、L、R )、\) スタックの最上位の積算値。オーダー\(F_M(L、R&LT)= P \)セクションの右端に対応し、大きな値はであるべきである([L、P-1 \ ] \) または\([P + 1、R ] \) 内部。したがってポップ・スタックの最上部、挿入\((I、L ,. 1-P)を、(I、P + 1、R&LT)\) そうするために時間をK、あなたは答えを見つけることができます。

STテーブルクエリがある\(O(1)\)ので、合計時間複雑である(O((N + K \ \))\ログN)

コード

#include<iostream>
#include<cstdio>
#include<cstring> 
#include<queue> 
#define maxn 500000 
#define maxlogn 25
using namespace std;
typedef long long ll;
int n,k,L,R;
struct sparse_table{
    int log2[maxn+5];
    int st[maxn+5][maxlogn+5];
    void ini(ll *a,int n){
        log2[0]=-1;
        for(int i=1;i<=n;i++) log2[i]=log2[i>>1]+1;
        for(int i=1;i<=n;i++) st[i][0]=i;
        for(int j=1;j<=log2[n]+1;j++){
            for(int i=1;i+(1<<(j-1))<=n;i++){
                if(a[st[i][j-1]]>a[st[i+(1<<(j-1))][j-1]]) st[i][j]=st[i][j-1];
                else st[i][j]=st[i+(1<<(j-1))][j-1];
            } 
        }
    }
    int query(ll *a,int l,int r){
        int k=log2[r-l+1];
        if(a[st[l][k]]>a[st[r-(1<<k)+1][k]]) return st[l][k];
        else return st[r-(1<<k)+1][k];
    }
}T;

int a[maxn+5];
ll sum[maxn+5];
struct node{
    int l;
    int r;
    int i;
    inline ll val(){
        return sum[T.query(sum,l,r)]-sum[i-1];
    }
    node(){
        
    } 
    node(int _i,int _l,int _r){
        i=_i;
        l=_l;
        r=_r;
    } 
    friend bool operator < (node p,node q){
        return p.val()<q.val();
    } 
};
priority_queue<node>q; 
int main(){
    scanf("%d %d %d %d",&n,&k,&L,&R);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    T.ini(sum,n);
    for(int i=1;i+L-1<=n;i++){
        q.push(node(i,i+L-1,min(i+R-1,n)));
    }
    ll ans=0;
    for(int i=1;i<=k;i++){
        node now=q.top();
        q.pop(); 
        ans+=now.val();
        int p=T.query(sum,now.l,now.r);
        if(p>now.l) q.push(node(now.i,now.l,p-1));
        if(p<now.r) q.push(node(now.i,p+1,now.r)); 
    }
    printf("%lld\n",ans); 
}

おすすめ

転載: www.cnblogs.com/birchtree/p/11516960.html