• 【题解】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 ( imes 1):一个喂养员喂连续的一片
    14:50 Observe( imes2):一个喂养员喂的连续的一片一定是按照(t(i)-dis(1,h_i))的升序最优
    15:00 Brute Force( imes 1): (O(n^2))DP,(dp(i,j))考虑了(i)个喂养员,带回前(j)只猫(按照(t(i)-dis(1,h_i))排序)
    15:30 Debug ( imes 1): (t(i)-dis(1,h_i))不需要对(0)(max)
    16:30 Solution( imes 1) 单调队列
    16:50 Solution( imes2) 斜率优化+单调队列
    吃饭 差点被阿
    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) imes 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 imes dis(1,j)+sum(j)) ]

    查询一个截距最小值。好像要单调队列维护。查到哪个(k)转移套到原式就好了。

    不过这里复杂度貌似(O(n)(kle 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;
          
    }
    
    
  • 相关阅读:
    深度解析VC中的消息传递机制(上)
    DLL的远程注入技术
    一些游戏编程的书[转]
    [转]小小C的C++之歌
    Windows Server 2008无法使用arp命令添加静态MAC绑定
    如何调用未公开的API函数[转]
    IOCP中的socket错误和资源释放处理方法
    TinyXML应用例子
    微软C/C++ 编译器选项参考
    [摘录]这几本游戏编程书籍你看过吗?
  • 原文地址:https://www.cnblogs.com/winlere/p/10994557.html
Copyright © 2020-2023  润新知