codeforce-311b:Cats Transport(dp+斜率優化)
阿新 • • 發佈:2019-02-20
題目大意:
有m只貓,他們分別會在某個時間在某座山上等飼養員來接它。你有p個飼養員,問你怎麼分配飼養員的出發時間可以讓所有貓等待的時間最小。
解題思路:
首先要預處理,貓到達某座山的時間減去飼養員從起始點到這座山的時間。文字難以說明,舉個例子,
起點是第一座山,還有山2還山3,山1到山2距離5,山2到山3距離2,第一隻貓在5小時的時候在山2,第二隻貓8小時的時候在山3.預處理減去距離之後,就變為了 2 1 ,那麼再排下序,1 2,飼養員這時從2點出發,不是可以恰好接到第一隻貓而第二隻貓需要等1小時。問題就轉化成每個貓一個值,每個飼養員一個值,時間就是每個貓找比他大的最近的飼養員,然後將他們差值加起來即可。
懂了這個dp方程就不多說了,感覺像是比較經典的斜率dp問題。我寫的是正常的二維dp陣列,應該能優化到一維,不過我也沒寫,
關於斜率dp,推薦一篇部落格,博主寫的非常仔細。自己就是在那學習的 部落格:斜率優化。
以下貼程式碼,
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include <map> #include <algorithm> #include <set> #include <functional> #define rank ra #define lson rt<<1 #define rson rt<<1|1 #define pb push_back using namespace std; typedef long long ll; ll INF=1e18+7; int n,m,p,i; ll d[100010],s[100010],t[100010]; ll dp[110][100010]; int q[100010]; ll getup(int k2,int k1) //斜率dp用到的地方 { ll g1=dp[i-1][k1]+s[k1]; ll g2=dp[i-1][k2]+s[k2]; return g2-g1; } ll getdown(int k2,int k1) //同上 { return k2-k1; } int main() { while(scanf("%d%d%d",&n,&m,&p)!=EOF) { for(i=2;i<=n;i++) { cin>>d[i]; d[i]+=d[i-1]; //預處理 } int qt; for(i=1;i<=m;i++) { cin>>qt>>t[i]; t[i]=t[i]-d[qt]; //預處理 } sort(t+1,t+1+m); for(i=1;i<=m;i++) s[i]=t[i]+s[i-1]; for(i=1;i<=m;i++) dp[0][i]=INF; int head=0,tail=0; for(i=1;i<=p;i++) { head=1; tail=0; for(int j=0;j<=m;j++) { while(head<tail&&getup(q[head+1],q[head])<=t[j]*getdown(q[head+1],q[head])) //斜率dp模板 head++; dp[i][j]=dp[i-1][q[head]]+(j-q[head])*t[j]-(s[j]-s[q[head]]); while(head<tail&&getup(j,q[tail])*getdown(q[tail],q[tail-1])<=getup(q[tail],q[tail-1])*getdown(j,q[tail])) tail--; q[++tail]=j; } } cout<<dp[p][m]<<endl; } }