はじめに▎
まず、当然の初見の元、元の友人は何ですか。
今日は、通常は呼ばれないんRMQ問題このようなものを学ぶしようとしているそれと人民元が、それは何を問題ではありませんか?小扁は薄くなるように述べています。
▎事前スキル:動的計画
同志は、しないでください、動的プログラミングを理解してすぐにここに突きます。
質問は何である▎RMQ
☞ 「定義」
呼び掛けRMQ(A、i、j)の数応答、列Aの数の長さn:RMQ(範囲最小/最大クエリ)問題を参照して 、(I、J <= n)をI、Jの列Aの添字の数を返します最小値(大きい)値に、つまり、RMQの問題は、ほとんどの値の範囲を見出すものです。(百度からコピー)
それは、与えられた(位置の固定および不変順)で数字、(数回)の束をあなたの範囲内の最大値/最小周期を求めて:あなたは、小さな雇用者の言葉を翻訳したくないと思います。
☞ 「問題解決:モデリングアルゴリズム」
RMQ問題のだけの種類は、このアルゴリズムではありません。
それが問題なので、すべてがシミュレーションアルゴリズム(ぶっきらぼうと呼ばれる暴力)スタートで開始し、その後、私たちが解決しなければならないが、どのように解決する方法を、解決します。
まずシミュレーションアルゴリズムを解決する方法を考え、もちろん、直接、一定の間隔を横断し、最大/最小聖歌を見つけることです。しかし、忘れてはいけない、この質問は何度も尋ねた、大規模なデータの問題を横断してきたことは全く不十分です。
この時点で、私は、動的プログラミングを依頼しました。
☞ 「問題解決:動的計画。」
なぜ我々は、動的プログラミングにそれを使うのですか?まず、この質問について考える:なぜ暴力は需要を満たすことができません。
あなたは確かに言う:これは単純な、遅い聖歌の暴力ではありません。
しかし、ここでどのように遅い暴力?スローでの暴力は完全に大規模な、多くのことが繰り返されるトラバーサルの全範囲を有効に利用することはありません。
それでは、それの大きなセクションを有効に利用することができますか?私たちは自然に動的計画法(ダイナミックプログラミングの範囲に属する感)を考えます。
繰り返し尋ねたので、その後、私たちのダイナミックなプログラミングはO(n個のnを記録)前処理およびO(1)クエリすることができ、我々は前処理しなければならない方向の変更、の話しました。
小さなシリーズで始まる、状態を設計する方法を考えるために、それは間隔の動的計画問題の一種であるから、そう思う、そしてFを聞かせて[i] [j]はに(I〜J間隔でバーの最大/最小数を表し例えば、最大数)、F自然状態遷移式である[I] [J] = MAX([I] [K] F、F [K + 1] [J])。(Kは私が〜セクションランダム配列の添字jのですが、小さな直列中間点を取ることを好みます)
その後、私は遅すぎる設計し、より良く、より効率的な通過の記事を改善するために設計された状態で見つかりました。立ち上がり部分に渡すがこのように処理されます:[i] [j]は2を表し、fは〜私のJ -1の範囲内の最大/最小数は、その後、我々は半分のポイントの前に自分の考えに従うことができ、それがこれです:
:最初のセクションとなるように終了位置から動的プログラミングの形で変更後のF [I] [J-1]およびF [I + 2 。J-1 ] [。-J 1] 偶数、奇数とは時々同じではありませんので、グラフのためにこれらの2つの式の小さなシリーズは、標準ではないことがあります。
そして、私たちが必要と最大値と最小値は非常に簡単です。
しかし、問題は再び、私たちはそれに直面どのように尋ねますか?
我々は、デジタル部(パワーの逆数)内のパワーのこの数は二つのセクションのサイズを比較することによって制限される二つの基礎ここで例示することができます。
その後、我々はちょうど2つの最大値と最小間隔を比較することができます。I Dにダイナミックプログラミングの形態の二つのセクションFであり、[X] [Y-(1 << [D]ログ)+ 1] F、[D]ログ] [ログ[D])にこれは、Y-X + 1を意味します。
さて、問題は再び、どのように対処するログは、のは、トップ10のログ処理数を見てみましょう:
調査の後と、[i]はログイン= [I 2 /] 1法律をログに記録し、プロのでしょう求める、我々は前処理の値をログに記録することができます。
☞ 「アルゴリズム非常に速く、なぜ我々は他のアルゴリズムそれが必要なのですか?"
実は、これは、このアルゴリズムの欠点は、数値の一部は、サポート期間の値を変更することはできませんので、まさにです。
ツリーラインは、フェンウィックツリーはこの欠点に独創的な解決策であること。
▎実用的な運動:羅区P1816の忠誠心(テンプレートのタイトル)
直接質問に騒ぎ、:
P1816の忠誠心
タイトル説明
サーバントはスマートでできる人です。彼は明確に自分のアカウントを作成するために、完全な金持ち、金持ちとして10年間働きました。要件は、執事のk回の1日アカウント、スマートで有能な執事、家政婦を覚えているので、常に豊富に満足します。しかし、いくつかの挑発に、金持ちや家政婦は疑問を持っていました。口座番号Bへ:だから彼は時々、...、それぞれ数1、2によると、忠実な執事に彼の口座を決定するために、特別なメソッドを使用して、家政婦の問題を依頼することを決め、問題は、そのようなことです最小合計は何ですか?家政婦は、彼は常にfalse問題だった回以上を依頼する時間を持っていなかったようにするために。
入出力フォーマット
入力フォーマット:
最初の行は、2つの入力数mを有し、nはM(M <= 100000)Tのアカウントを発現し、問題がn個有し、Nを表し、n <= 100000。
それぞれ二行数m、マネー口座数
N、N後列は問題があり、各ラインは、二つの図は、アカウント数の終わりの始まりを示しています。
出力フォーマット:
各質問への回答の出力ファイル。具体的な例を見ます。
サンプル入力と出力
この質問は非常によく行われますが、それはテンプレートのタイトルですので、私は直接コードに、説明しています。
1つの#include <iostreamの> 2 使用して 名前空間STDを、 3 int型 M、N、[ 100000 [F]、100000 ] [ 100 ]、X、Y、ログイン[ 100000 ]。 4 INT メイン() 5 { 6 CIN >> M >> N。 7 のために(int型 I = 1 ; I <= M; iは++ ) 8 { 9 CIN >> [I]。 10 F [i]が[ 0 ] = [I]を、 11 } 12 のために(INTの J = 1 ; J <= 16 ; J ++ ) 13 のための(INT I = 1、I +(1 << J) - 1 <= M; iは++ ) 14 F [I] [J] =分(F [i]が[J- 1 ]、F [iが+(1 <<(J- 1))] [J- 1 ])。 15 ログ[ 1 ] = 0 。 16 のために(int型 I = 2 ; iが= < 100000 ;私++ ) 17 ログ[I] = [I /ログ2 ] + 1 。 18 用(int型 i = 1 ; iが<= N; iが++ ) 19 { 20 CIN >> X >> Y。 21 int型 D = Y-X + 1 。 22 COUT <<分([X] [ログイン[D] F、F [Y-(1 << [D])+ログイン1 [D]ログ])<< " " 。 23 } 24 リターン 0 。 25 }
▎実用的な運動:スルー1541:〔実施例1〕区間最大値の列の数(タイトルテンプレート)
直接質問に騒ぎ、:
[実施例1]区間最大値系列:1541
制限時間:1000ミリ秒のメモリ制限:524288キロバイト
で番号638:224番号を提出
説明[タイトル]
数字の文字列を入力し、あなた Mは、それぞれがあなたに2つの数値を与える尋ねる、頼みます X、Y、言うことを尋ねます Xへ この範囲内のYの最大数。
[Enter]を
二つの整数の最初の行 N、M及び数が問い合わされるべき桁数を表します。
次に、行動 数N。
次 M行、各行は2つの整数を有しています X,Y。
【输出】
输出共 M 行,每行输出一个数。
【输入样例】
10 2 3 2 4 5 6 8 1 2 9 7 1 4 3 8
【输出样例】
5 8
【提示】
数据范围与提示:
对于全部数据,1≤N≤105,1≤M≤106,1≤X≤Y≤N。数字不超过 C/C++ 的 int 范围。
【来源】
这道题只要把忠诚的代码改成max就可以了(还稍微有点其他细节),注意会卡常数,不能用cin和cout。代码如下:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int m,n,a[1000000],f[1000000][100],x,y,log[1000000]; 5 int main() 6 { 7 scanf("%d%d",&m,&n); 8 for(int i=1;i<=m;i++) 9 { 10 scanf("%d",&a[i]); 11 f[i][0]=a[i]; 12 } 13 for(int j=1;j<=18;j++) 14 for(int i=1;i+(1<<j)-1<=m;i++) 15 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 16 log[1]=0; 17 for(int i=2;i<=m;i++) 18 log[i]=log[i>>1]+1; 19 for(int i=1;i<=n;i++) 20 { 21 scanf("%d%d",&x,&y); 22 int d=y-x+1; 23 printf("%d \n",max(f[x][log[d]],f[y-(1<<log[d])+1][log[d]])) ; 24 } 25 return 0; 26 }