質問の意味:N人がいる、誰もが服の一部が洗濯を必要とし、手洗いは、tは時間を過ごす所有することができている、あなたはまた、それぞれの時間は、人が唯一最大の洗浄服を持つことができる、つまり、洗濯機、洗濯機、一つだけを使用することができます。今、あなたは洗濯誰もが服を洗濯するとき、洗濯機の尋ね洗浄時間は、すべての最短時間で1、2 ....トンある最も早い時間を、開始することができます。
アイデア:時間洗濯物によってソートされたすべてのための最初の私たちの考えることはまず、簡単に。私たちは、究極のボトルネック洗濯時間は間違いなく背後で見つかったので、我々は、総洗濯最短時間となるように洗濯機を使用する方法を検討してください。まず、それは最後の人の時間の衣服の洗濯機は、<=トン、そして最後の洗浄服は合計時間をすることはありませんので、洗濯機の洗濯服を使用する必要がありますが長いです、だけ短縮することができます。同様に、最後の人が洗濯機を使用する場合と最後から二番目の個人は、洗濯機の確かに最後から二番目の個人的な使用を競合していません。個人が最後から二番目の洗濯機を取らない場合には、人々の前で洗濯機を使用する必要はありませんでした、最後から二番目の個々の時間ので、確かに以上洗濯人々の前で、時間は最後から二番目の最後から二番目の個人または体内で唯一の最後のボトルネックをしてもよいです人物A。ように、我々は見つけることができます。最後に、洗濯機のヒト配列は、確かに元のシーケンスの接尾辞です。だから、現在のxに対して、どのように人々は洗濯機が何に使用するかを決定するには?1:Iから - 1時間制限個々ハンド:i番目の個体開始を仮定し、i番目の個別の洗浄開始時刻の設定B [i]は、衣類を洗浄し、制限時間は、2つの方法であってもよいB [I - 1] + T。2:洗濯機の終了時刻の背後にある人々と。それを数える方法終了時間?* X、当社および将来のすべての私 - 私たちは、[I] +(I + 1〜N)私は洗濯機を使うようになった人は、理想的な状況は、彼がマシンの他の人が使用することができ、洗濯を費やしたということで、その後の時間をbであると仮定します人は、理想的な状態の時間を考えられている最大値は、実際の終了時刻であるかかります。( - + T、MAX(B [K] +(N - K + 1)* X)のb [1 I])(> = I K)我々は、洗濯機の開始時刻からのヒトiが最大であることを見出しました。見つけやすい、B [K] + tは、単調増加関数です。maxは(B [K] +(N - K + 1)* x)は単調減少関数であり、どちらもmaxは単機能トラフで取る、底が最適解です。これは厳密に単調な関数は三分の一、唯一の暴力列挙することはできませんようではありません。次いで、特定の時間複雑度はO(N)AはX。しかし、今のn xはどのように行う、がありますか?私たちは、いつでも判定時間後、私たちは一番下、Xマイナス1へのポインタを使用することができ、xの小さい方で、底が徐々に前方に移動し、xが時間tに等しいときに、底面が最後になければならないことがわかりましたそれは前進している場合トラフは、前方ではありません。[ - 1 i]が+ tを一定に維持されていない、[保存は最大xはその後、新たな問題がB、発生する(B [K] +(N - * K + 1)x))をすべて再計算持っているように見えますか?線形横軸は、このセグメントツリーは嘘を使用することができる場合、縦軸がパイルに判定された場合切片として傾き、B [K]として、K + 1、問題は最大値への変換を見つけることである - Nが場合(ログ(N))時間O.を行います
コード:
#include <ビット/ STDC ++ H> に#define LL長い長い 0x3f3f3f3fの#define INF の#define LS(<< 1 O) の#define RS(O << 1 | 1) 使用して名前空間std。 const int型MAXN = 1000010; 構造体の線{ ダブルK、B。 }。 線A [MAXN]。 int型のTOT; 構造体ノード{ int型のID。 }。 ノードTR [MAXN * 4]。 二重get_pos(int型のx、int型のY){ 戻り[X]・K * Y + [X] .B。 } 二重交差(int型のx、int型のY){ リターン([X] .B - [Y] .B)/([Y] .K - [X]・K)。 } ボイドのinit(int型、L、O INT、INT R){ TR [O] .ID = 0。 (L == R)戻った場合。 INT半ば=(L + R)>> 1。 INIT(LS、L、MID)。 INIT(RS、ミッド+ 1、R)。 } ボイド更新(INT O、int型のL、int型のR、今INT){ {([O] .ID TR!)場合 =今TR [O] .ID。 返します。 } INT X = TR [O] .ID。 二重L1 = get_pos(今、L)、R1 = get_pos(ここで、R) 二重L2 = get_pos(X、L)、R2 = get_pos(X、R)。 (L1 <L2 = && R1 <= R2){もし 返します。 } そうであれば(L1> L2 && R1> R2){ TR [O] .ID =今。 返します。 } INT半ば=(L + R)>> 1。 二重Y =交差(ここで、X)。 もし(Y <= MID)更新(LS、L、中、R1> R2 X:今?)。 他の更新(RS、ミッド+ 1、R、L1> L2のx:今?)。 IF((Y <=ミッド&& R1> R2)||(Y>中間&& L1> TR [O] .ID =今。 } INTクエリ(INT O、int型のL、int型のR、int型のPOS){ IF(L == R){ 戻りTR [O] .ID。 } INT半ば=(L + R)>> 1、ANS = 0。 IF(POS <= MID)ANS =クエリ(LS、L、中間、POS)。 他のANS =クエリ(RS、ミッド+ 1、R、POS); ;戻りANS(!.ID [O] TR)であれば INT X = TR [O] .ID。 IF(get_pos(X、POS)> get_pos(ANS、POS))リターンX。 他のリターンANS; } int型B [MAXN]。 LL RES [MAXN]。 メインINT(){ int型のn; LLのトン。 一方、(〜のscanf( "%d個の%のLLD"、&N、&T)){ INIT(1、1、T); 以下のために(INT i = 1; iが<= N; iが++){ scanf関数( "%dを" &B [I])。 } ソート(B + 1、B + 1個の+ N)。 以下のために{(INT i = 1; iが++; iが<= N) [I] =(ライン){(ダブル)N - I + 1、(ダブル)B [I]}。 } B [0] = -t。 LL TMP、TMP1。 アップデート(1、1、T、N)。 INT P = N - 1。 ための式(I = tをint型、I> = 1; i--){ ながら(1){ int型ANS =クエリ(1、1、T、I)。 LLのT1 = bの[ANS] +((LL)N - ANS + 1)* I。 TMP = MAX(T1、B [P] + T)。 もし(P == 0)ブレーク。 TMP1 = MAX(MAX(T1、B [P] +((LL)N - 、P + 1)* I)、B [P - 1] + T)。 IF(TMP1 <= TMP){ 更新(1、1、T、P)。 P--; } 他に休憩; } RES [i]はTMPを=。 } (i = 1をint型、iがTを<; Iは++){ため のprintf( "%のLLD"、RESが[I]); } のprintf( "%のLLDを\ n"、RES [T])。 } }