[アルゴリズムステンシル]最適化スロープ
前回のブログでは、斜面Jidao例を最適化。しかし、これらの例は、に対処するための「セグメント」として「状態」です。最後に、私は、二次元平面よりよい取引上の点として求め、または状態。
スロープの最適化について話を例としてレースをシミュレートするために、ここで質問昨日。
Harry_bhによって書かれたこの記事のほとんどは、承認したいと思います。
\(Dp_ {I、J} = Dp_ {I-1、K} \)
\(dp_i = dp'_j +ヴァル(IJ) - (S_I-s_j)\)
仮定すると、\(j個\)は、最適な意思決定ポイントであります
仮定(<K \ J)\
いずれかのために\(K \)満足
\ [dp_j +ヴァル(IJ) (S_I-s_j)\当量dp_k +ヴァル(IK) - - (S_I-S_K)\\ dp_j-dp_k + s_j-S_Kの\の当量のValを(JK)\\ \のcfrac {dp_j -dp_k + s_j-S_K} {JK} \ GEQヴァル\\ \]
彼は、2つの点で何の意味\((J、dp_j + S_j)\) 、\((K、dp_k + S_K)\)に形成された直線の傾き
その場合は\(J \)より\(K \) 、その後、より良い、スロープ満足。。。。
あなたは、キューを維持するので、我々はチームがその最初の要素の設定としてチーム最初の要素は、私たちが望む最適な意思決定ポイントであるようにしたい\(最初のポイントの斜面と第2の点\ GEQヴァル\を)。そして\(ヴァル\)が単調に増加しているので、私は斜面の点にドアキューと各ポイントを作るために必要なのは、単調増加(すなわち、凸包)です。
我々かどうかを決定する必要がある、末尾に新しい要素を挿入する\(尾部、尾-1 \ ) 傾きがより大きい\(挿入エレメント、テール1 \)勾配は、する必要がある場合(尾を\)\削除アウト。(具体的な、ということを意味している\(尾\)状態とは、このキューの自然の中で要素を挿入することが優れていないが、彼の背後にあるすべての状態の状態ですべてのチームよりも優れています)
コード:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
#define maxn (int)(1e5+100)
ll dp[1005][50020],dis[maxn],tim[50020],n,m,p,pre[maxn],h[maxn],t[maxn],queue[maxn];
using namespace std;
int main() {
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=2;i<=n;i++){scanf("%lld",&dis[i]);dis[i]+=dis[i-1];}
for(int i=1;i<=m;i++){scanf("%lld%lld",&h[i],&t[i]);tim[i]=t[i]-dis[h[i]];}
sort(tim+1,tim+1+m);for(int i=1;i<=m;i++)pre[i]=tim[i]+pre[i-1];
memset(dp,0x3f,sizeof(dp));dp[0][0]=0;
for(int i=1;i<=p;i++) {
ll head=1,tail=0;
for(int j=0;j<=m;j++) {
while(head<tail&&(dp[i-1][queue[head]]+pre[queue[head]]-dp[i-1][queue[head+1]]-pre[queue[head+1]])>tim[j]*(queue[head]-queue[head+1]))head++;
dp[i][j]=dp[i-1][queue[head]]+tim[j]*(j-queue[head])-(pre[j]-pre[queue[head]]);
while(head<tail&&(dp[i-1][queue[tail-1]]+pre[queue[tail-1]]-dp[i-1][queue[tail]]-pre[queue[tail]])*(queue[tail-1]-j)>(dp[i-1][queue[tail-1]]+pre[queue[tail-1]]-dp[i-1][j]-pre[j])*(queue[tail-1]-queue[tail]))tail--;
queue[++tail]=j;
}
}
printf("%lld",dp[p][m]);
}