P1484の木 - プライオリティキューデータ構造

私たちは、午後に木を植え、そして最終的には(あなたがはっきりポイント(目に見えない目に見えない)を話すことができない問題に(問題解決の偉大な神をありがとう)(溶液))それを与えました。

あなたは木を持っているK、あなたができる種類の直線で、あなたは、この値を得ることができます木を置けば、それぞれの場所には、値を持っていますが、条件は、任意の2本の隣接する木がありません。

もちろん、あなたは0をkに任意の木を植えることができます。

どのようにそれを行うには?この質問は、(まれ)問題の良心であり、私が選択したか、選択されていない。この位置を列挙し、脳の暴力なしで最初の20分を書きました。

書式#include <cstdioを> 
する#include <CStringの> 
の#include <アルゴリズム>
 使用して 名前空間はstdを、
const  int型 MAXN = 5E5 + 10 
typedefの長い 長いLL。
int型N、K。
INT [MAXN]。
INT [MAXN] B。
ANS LL; 
LLのCNT; 
ボイド DFS(INT X)
{ 
    場合(X == N + 1 
    { 
        LL和 = 0 int型 NUM = 0 ;
        以下のためのint型i = 1 ; iは= <N; iは++ 
        { 
            場合(B [I] == 1件の && B [I- 1 ] == 1リターン;
            もし(B [I] == 1 
            { 
                NUM ++ 場合(NUM> k)を返します + = (LL)[I]。
            } 
        } 
        ANS = MAX(ANS、合計)。
        返します
    } 
    [X] B = 0 ; DFS(X + 1件の)。
    B [X] = 1 ; DFS(X + 1 )。
} 

int型のmain()
{ 
    scanf関数(" %D%dの"、&​​N&K)。
    以下のためにint型私= 1 ; iが<= N; iが++)のscanf(" %dの"、および[I])。
    DFS(1 )。
    printf(" %のLLD " 、ANS)。
    リターン 0 ; 
}

しかし、あなたは20ポイントに喜んで、これは直線であると考えることができますどのように、あなたはDPは、わずか50ポイントでパスを貼り付け使用することができます。

[I] [j]は、現在位置1からI jの木植え最大値の合計を表すfはそれがあります。

電流は木、[I-1] [j]はF直接コピーされていない場合、彼らは木を望むなら(それは隣接していないため)、[I-2] [J-1] fをコピーします

書式#include <cstdioを> 
する#include <CStringの> 
の#include <アルゴリズム>
 使用して 名前空間はstdを、
const  int型 MAXN = 5E5 + 10 
typedefの長い 長いLL。
int型N、K。
LL [MAXN]。
ANS LL; 
[F LL 6010 ] [ 3010 ]。
INT メイン()
{ 
    scanf関数(" %d個の%のD "、&​​N&K)。
    int型 I = 1のscanf(私は++; iが<= N)" %のLLD "、& [I])。
    [F 1 ] [ 1 ] = [ 1 ]。
    以下のためにint型 I = 2 ; iは++; iが<= N 
    { 
        ためint型の J = 1 ; J <= kであり、j ++ 
        { 
            F [I] [J] = MAX([I-F 1 ] [j]は、 F [I- 2 ] [J- 1 ] + [I])。
            ANS = MAX(ANS、F [i]は[J])。
        } 
    } 
    のprintf(" %のLLD " 、ANS)。
    リターン 0 ; 
}

時空の制約が、私は、ああ良いガスから抜け出すことはできません。

最後に、私は(目が光を発する)問題への解決策を開設しました

三ヶ月後……

私たちは、誰のどのような種類を制御していない人、後者は、限り最大値として、

私たちは、これがそれから来ているか、プライオリティキューを使用できますか?連続面3(第一の又は自由端位置)の数は、符号1,2,3を参照します。

私たちは第二の穴を選択した場合は、その後、1,3スクラップこと。

(!!あなたが達成するためにプライオリティキューを)(私はこの種のものを分析したくない表す);あなたは1.3を選択した場合は、2を選出することはできません

私たちは、ヒープのトップは、我々が探している最大でデフォルト、しかし、我々はいくつかの処理を通過する必要があります。

R [I] = I + 1;左右の各点の位置を端部はL [I] = I-1に記録されています

最初のピットに投げ込まN、その後、ヒープの上部には、我々はANS + = valを取り出して、その最大値になります(なぜ、1,3-行う方法を?)

我々はオプション1、3、1、3を選択することはできませんので、それは問題ではありません、我々は選択しないと、2の値が取り出され、その後、2の値を更新し、

ヴァル[2] = valの[1] +ヴァル[3] -Val [2];(ANS値を更新する必要があります)

しかし、我々は繰り返しを避けるために選択し、VIS [1] = VIS [3] = 1;(特別ではないアクセス)

3の3つのグループに分けグループをしているのと同等であり、我々はあなたが2アップデート(0,2,4になるための同等のもの)を配置したい値についての最新情報を掲載します

実際には、我々は最後まで3つの接続されたエンドのグループで問題が解決されます(私たちは1,3を選択したい場合は、私たちはこの時間を更新するパターン、再び2 0,2,4である、彼らは接続されません。)

(1,3及び0,4から選択すると比較されました)

処理が完了しています。

杭は、行に終了し、負である場合には、

書式#include <cstdioを> 
する#include <CStringの> 
の#include <キュー> 
の#include <アルゴリズム>
 使用して 名前空間はstdを、
const  int型 MAXN = 5E5 + 10 
typedefの長い 長いLL。
INT [MAXN]。
int型N、K。
INTをL [MAXN]、R [MAXN]。
PRIORITY_QUEUE <ペア< int型int型 >> Q; 
ANS LL; 
int型VIS [MAXN]。
INT メイン()
{ 
    scanf関数(" %d個の%のD "、&​​N&K)。
    以下のためにint型 i = 1 ; iが<= N; iが++ 
    { 
        scanf関数(" %dを"[I])。
        // [I] .val = -a [I] .val。
        q.push(make_pair([i]は、I))。
        L [I] = I- 1 
        R [I] = I + 1 
    } 
    R [ 0 ] = 1 ; Lが[N + 1 ] = N。
    一方、(k-- 
    { 
        一方(VIS [q.top()秒])q.pop();
        INT X = q.top()最初。
        int型I = q.top()は、第2。
        q.pop(); 
        もし(X < 0ブレーク
        ANSは + = (LL)X; 
        [I] [L [i]は] + [R [I] = - [I]を、
        VIS [L [I] = 1 ; VIS [R [I] = 1 
        L [I] = 1 [L [I]、R [L [I] = I。
        R [I] = R [R [I]、L [R [I] = I。
        q.push(make_pair([i]は、I))。
    } 
    のprintf(" %のLLD " 、ANS)。
    リターン 0 ; 
}

 これらの慣行とコードサイズを見て、あなたは(それを行うのは難しいです)(〜をエスケープ)この問題は思います。

 

おすすめ

転載: www.cnblogs.com/WHFF521/p/11528737.html