[ソリューション]タスクスケジューリング問題(スロープの最適化)

[ SDOI2012]タスク・スケジューリング

スロープの最適化スターター質問:

セット\(F(X)\)\(F(X)\)コンジュゲーションと、\(T(X)\)\(T(X)\)接頭辞と。\(DP(I)\)第一の完了を示す\を(iは\)委任最小コスト転送:

\(DP(I)= \ \分{DP(J)+ F(J + 1)\回(S + T(1)-T(J))\} \)

削除:

  • そして\(jは\)は何の関係もありません:なし
  • そして、唯一の\(J \)関連:\(DP(J)+ F(J + 1)\タイムズ(ST(J))\)
  • そして\(I、J \)関連:\(F(J + 1)\タイムズT(I)\。)

私たちは発見し、(J \)\直接前処理に関連することができ、質問は今決定することです\(私は\)素早く見つける方法\(j個の\を)

オーダー\(y_j = DP(J)+ F(J + 1)\タイムズ(ST(J))\)、\ (X - jが= F(J + 1)\。) 元の式のように書くことができる:
[DP(I \ )= y_j + x_jt(I) \]

変換式をクリックして
\ [y_j = -t(I) X - jが+ DP(I)\]

今識別してしまう問題\は(私は\) すぐに前を検索します\(j個\)となるように\(DP(I)\)最低

直線で、それは私がスロープの平面に翻訳を持っているとなり、この事\( - T(i)は\ ) 今の点を見つけ、直線である\((X - jが、y_jは)\ ) になり過ぎますこの時点での勾配である\( - T(I)\ ) 直線の切片できるだけ小さいです。

青:スロープ\( - T(I)\ ) ライン

パープルポイント:\((X - jが、y_j)\)

もちろん、中に見ることができます\(のy \)負の無限大の車軸がゆっくりと直線(切片が徐々に大きくなる)に移動しているが、このラインは、我々はそれを設定し、突然のポイントを通過しますこの切片で切片の最小です。明らかに、特定のポイント上記本凸包、この点の左右の斜面には、右(負の傾き)に大きく、小さいままにしなければなりません。

ダイナミックなメンテナンスは凸包のように見えます。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
int n,s;
const int maxn=3e5+5;
int Ti[maxn],Fi[maxn];
ll st[maxn],sf[maxn];
ll x[maxn],y[maxn],q[maxn],dp[maxn];
int cnt;

inline ll getval(const int&i,const int&j){
      return dp[j]+sf[j+1]*(s+st[i]-st[j]);
}

inline bool chek0(const int&i,const int&j,const ll&k){
      return (long double)1.0*((y[i]+dp[i])-(y[j]+dp[j]))*(x[i]-x[k])<=(long double)1.0*((y[i]+dp[i])-(y[k]+dp[k]))*(x[i]-x[j]);
}

inline bool chek(const int&i,const int&j,const ll&k){
      return (long double)1.0*(y[i]+dp[i])-(y[j]+dp[j])<=(long double)1.0*k*(x[i]-x[j]);
}

inline int lookup(const ll&k){
      register int l=1,r=cnt-1,ret=cnt,mid;
      while(l<=r){
        mid=(l+r)>>1;
        if(chek(q[mid],q[mid+1],k))
          r=mid-1,ret=mid;
        else l=mid+1;
      }
      return q[ret];
}
int main(){
      
      n=qr();s=qr();
      for(register int t=1;t<=n;++t)
        Ti[t]=qr(),Fi[t]=qr(),st[t]=st[t-1]+Ti[t];
      for(register int t=n;t>=0;--t) sf[t]=sf[t+1]+Fi[t];
      for(register int t=0;t<=n;++t) y[t]=sf[t+1]*(s-st[t]),x[t]=sf[t+1];
      q[cnt=1]=0;
      for(register int t=1;t<=n;++t){
        dp[t]=getval(t,lookup(-st[t]));
        while(cnt>1&&chek0(q[cnt-1],q[cnt],t)) --cnt;
        q[++cnt]=t;
      }
      cout<<dp[n]<<endl;
      return 0;
}

おすすめ

転載: www.cnblogs.com/winlere/p/10994580.html