【题解】Cats Transport (斜率优化+单调队列)

【题解】Cats Transport (斜率优化+单调队列)

# When Who Problem Lang Verdict Time Memory
55331572 Jun/09/2019 19:18UTC+8 Winlere D - Cats Transport GNU C++11 Accepted 405 ms 84200 KB

思考的过程很艰难,想清楚之后就不难做了。记录一下思路过程。

时间 事件
14:00 开始审题
14:15 手玩样例
14:30 Observe \(\times 1\):一个喂养员喂连续的一片
14:50 Observe\(\times2\):一个喂养员喂的连续的一片一定是按照\(t(i)-dis(1,h_i)\)的升序最优
15:00 Brute Force\(\times 1\): \(O(n^2)\)DP,\(dp(i,j)\)考虑了\(i\)个喂养员,带回前\(j\)只猫(按照\(t(i)-dis(1,h_i)\)排序)
15:30 Debug \(\times 1\): \(t(i)-dis(1,h_i)\)不需要对\(0\)取\(max\)
16:30 Solution\(\times 1\) 单调队列
16:50 Solution\(\times2\) 斜率优化+单调队列
吃饭 差点被阿
19:18 Accepted

想的时间占了很多,幸运的是一开始的\(O(n^2)\)DP的方向是对的,一个小时写出暴力还是很赚的。就是后面想什么单调队列,应该可以直接想到斜率优化的,\(n^2\)转\(n \log n\)太常见了。

有两个Observe比较显然就不证明了。\(t_i-dis(1,i)\)可以代表的含义是喂养员最早出来的时刻。

\(O(n^2)\)的转移:
\[ dp(i,j)=\min\{dp(i-1,j),dp(i-1,k)+(j-k)\times t_j-(sum(j)-sum(k))\} \\ sum(i)=\Sigma_{j=1}^it_j-dis(1,j) \]
拆开\(j,k\)直接变成一个斜率优化的套路式。

\(x_k=k,y_k=dp(i-1,k)+sum(k)\)

原式变为:
\[ y_k=t_jx_k+(dp(j)-j\times dis(1,j)+sum(j)) \]
查询一个截距最小值。好像要单调队列维护。查到哪个\(k\)转移套到原式就好了。

不过这里复杂度貌似\(O(n)(k\le 100)\)

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

using namespace std;  typedef long long ll;
inline ll qr(){
      register ll 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;
}
const int maxn=1e5+5;
int n,m,p;
int dis[maxn];
ll sumd[maxn];
ll sumdata[maxn];
ll x[maxn];
ll y[maxn];
ll dp[101][maxn];
struct NODE{
      int pos,time;
      ll limit;
      NODE(){limit=pos=time=0;}
      inline bool operator <(const NODE&a)const{return limit<a.limit;}
      inline void scan(){
        pos=qr();time=qr();
        limit=time-sumd[pos];
      }
}data[maxn];


typedef deque<int>::iterator it;
deque < int > q;

int main(){
      
      n=qr();m=qr();p=qr();
      for(register int t=2;t<=n;++t)
        sumd[t]=(dis[t]=qr())+sumd[t-1];
      for(register int t=1;t<=m;++t)
        data[t].scan();
      sort(data+1,data+m+1);
      for(register int t=1;t<=m;++t) sumdata[t]=data[t].limit+sumdata[t-1];
      memset(dp,5,sizeof dp);
      dp[0][0]=0;
      it ita;
      for(register int i=0;i<=m;++i)
        x[i]=i;
      for(register int t=1;t<=p;++t){
        for(register int i=0;i<=m;++i){
          dp[t][i]=dp[t-1][i];
          y[i]=dp[t-1][i]+sumdata[i];
        }
        q.clear();
        for(register int i=1;i<=m;++i){
          q.push_back(i-1);
          ita=q.begin();
          while(q.size()>1&&y[*(ita+1)]-y[*ita]<=1ll*data[i].limit*((*(ita+1))-(*ita))) q.pop_front(),ita=q.begin();
          register int j=q.front();
          dp[t][i]=min(dp[t][i],dp[t-1][j]+1ll*(i-j)*data[i].limit-(sumdata[i]-sumdata[j]));
          ita=q.end()-1;
          while(q.size()>1&&(y[*ita]-1ll*y[*(ita-1)])*(i-(*ita))>=1ll*(y[i]-y[*ita])*((*ita)-(*(ita-1)))) q.pop_back(),ita=q.end()-1;;
        }
      }
      cout<<dp[p][m]<<endl;
      return 0;
      
}
上一篇:Cats Transport


下一篇:Received message from unsupported version: [6.4.3] minimal compatible version is: [6.7.0]