https://www.luogu.com.cn/problem/P5017
この質問は多くの奇妙なアイデアを使用しています
(多分私は無知です)
解決策:
抽象トピック:
それはおそらく時間を示す数直線であるため、各クラスメートの到着時刻は数直線上の点です。
車両を特定の時間に配置することは、特定のポイントで左開きと右閉じのセクションを取得することと同じです。
待ち時間は、ポイントから右への距離に等しい
この線形dp方程式が出てきます
式を編集する方法はありません)
f iを再帰する前 に、自動車の紛失時間を現時点でのみスケジュールするための前処理が必要です
それは
次に、接頭辞と最適化により時間の複雑さを軽減することを考えました
2つのsum [] cnt []配列が定義されています。これらは、プレフィックスの合計とプレフィックスポイントの数です。
したがって、dpを書き換えます
O(t 2)
次に、この大まかなアルゴリズムを使用して50 ...
シンプルな最適化
元のj∈( -∞、i -m)は(i-2 * m、i-m)に変更できます
O(mt)
間隔が2mを超えると、待ち時間の短縮に対応するために、車の余分な往復時間が必要になるためです。
それから私は70を混ぜました
もう一度最適化する
(i-m、i]にポイントがない場合は、
cnt [i]はcnt [i-m]と同等
次に、直接f [i] = f [i-m]
それから私たちはACです
時間の複雑さはO(nm 2 + t)に最適化されています
1 #include <iostream> 2 #include <cstdio> 3 4 名前空間std を使用 。 5 6 int sum [ 4000005 ]、cnt [ 4000005 ]、f [ 4000005 ]; 7 8 int main() 9 { 10 ios_base :: sync_with_stdio(false ); 11 cout.tie(NULL); 12 int n、m; 13 cin >> n >> m; 14 int x; 15 int aux = 1e7; 16 整数 maxn = 0 ; 17 for(register int i = 1 ; i <= n; i ++ ) 18 { 19 cin >> x; maxn = max(maxn、x); 20 cnt [x] ++; sum [x] + = x; 21 } 22 for(register int i = 1 ; i <maxn + m; i ++ ) 23 cnt [i] + = cnt [i- 1 ]、sum [i] + = sum [i- 1 ]; 24 25 for(register int i = 0 ; i <maxn + m; i ++ ){ 26 if(i> = m && cnt [im] == cnt [i]){f [i] = f [im]; 続行;} 27 f [i] = cnt [i] * i- sum [i]; 28 for(register int j =(im-m + 1 > 0)?im-m + 1:0 ; j <= im; j ++ ) 29 { 30 // if(im-m + 1 <0)j = 0; 31 f [i] = min(f [i]、f [j] +(cnt [i] -cnt [j])* i-(sum [i] -sum [j])); 32 } 33 } 34 35 for(register int i = maxn; i <maxn + m; i ++)aux =min(aux、f [i]); 36 コスト<< aux; 37 }