zoukankan      html  css  js  c++  java
  • CF311B Cats Transport

    XVII.CF311B Cats Transport

    推式子时间到~~~

    我们首先对题目中的\(d_i\)做前缀和,求出每座山距离原点距离;

    然后对于第\(i\)只猫,如果一个饲养员在\(t_i-d_{h_i}\)时刻以后出发就可以接到它;

    注意,饲养员可以在负时刻就出发!!!我之前想多了以为只能在非负时刻出发而纳闷了好半天

    我们设\(t_i-d_{h_i}\)为新的\(t_i\),然后将所有的\(t_i\)排序。

    然后开始DP:

    \(f[i][j]\)表示:前\(i\)只猫,派出\(j\)个人,的最优时间。再设\(s_i\)表示\(t_i\)的前缀和。

    则有\(f[i][j]=\min\limits_{k=0}^{i-1}\{f[k][j-1]+t_i*(i-k)-(s_i-s_k)\}\)

    我们这样就可以写出\(O(m^2p)\)的代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,m,p,d[100100],t[100100],s[100100],f[100100][110],qwq=0x3f3f3f3f3f3f3f3f;
    signed main(){
    	scanf("%lld%lld%lld",&n,&m,&p),memset(f,0x3f3f3f3f,sizeof(f));
    	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
    //	for(int i=1;i<=n;i++)printf("%lld ",d[i]);puts("");
    	for(int i=1,x,y;i<=m;i++)scanf("%lld%lld",&x,&y),t[i]=y-d[x];
    //	printf("%lld\n",res);
    //	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
    	sort(t+1,t+m+1);
    	for(int i=1;i<=m;i++)s[i]=s[i-1]+t[i];
    //	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
    	f[0][0]=0;
    	for(int j=1;j<=p;j++)for(int i=1;i<=m;i++)for(int k=0;k<i;k++)f[i][j]=min(f[i][j],f[k][j-1]+(i-k)*t[i]-(s[i]-s[k]));
    	for(int i=1;i<=p;i++)qwq=min(qwq,f[m][i]);
    	printf("%lld\n",qwq);
    	return 0;
    }
    

    然后考虑斜率优化一下:

    \(f[i][j]\)中,我们按照列优先(先枚举\(j\))的顺序进行DP;并且,设\(f[i][j-1]\)\(F[i]\)

    \(j<k<i\)(不是同一个\(j\))。则如果\(j\)\(k\)优,则有:

    \(F_j+t_i*(i-j)-(s_i-s_j)<F_k+t_i*(i-k)-(s_i-s_k)\)

    拆开

    \(F_j+i*t_i-j*t_i-s_i+s_j<F_k+i*t_i-k*t_i-s_i-s_k\)

    抵消

    \(F_j-j*t_i+s_j<F_k-k*t_i+s_k\)

    移项

    \(F_j-F_k+s_j-s_k<(j-k)*t_i\)

    除过去(注意\(j-k\)是负数)

    \(\dfrac{F_j-F_k+s_j-s_k}{j-k}>t_i\)

    右边的\(t_i\)是递增的(排过序了),因此可以采用单调队列维护斜率;然后维护一个下凸壳即可。复杂度\(O(mp)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,m,p,d[100100],t[100100],s[100100],f[100100][110],qwq=0x3f3f3f3f3f3f3f3f,l,r,q[100100];
    signed main(){
    	scanf("%lld%lld%lld",&n,&m,&p),memset(f,0x3f3f3f3f,sizeof(f));
    	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
    //	for(int i=1;i<=n;i++)printf("%lld ",d[i]);puts("");
    	for(int i=1,x,y;i<=m;i++)scanf("%lld%lld",&x,&y),t[i]=y-d[x];
    //	printf("%lld\n",res);
    //	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
    	sort(t+1,t+m+1);
    	for(int i=1;i<=m;i++)s[i]=s[i-1]+t[i];
    //	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
    	f[0][0]=0;
    	for(int j=1;j<=p;j++){
    		l=r=0;
    		for(int i=1;i<=m;i++){
    			while(r-l&&(f[q[l]][j-1]-f[q[l+1]][j-1]+s[q[l]]-s[q[l+1]])>=(q[l]-q[l+1])*t[i])l++;
    			f[i][j]=f[q[l]][j-1]+(i-q[l])*t[i]-(s[i]-s[q[l]]);
    			while(r-l&&(f[q[r-1]][j-1]-f[q[r]][j-1]+s[q[r-1]]-s[q[r]])*(q[r]-i)>=(f[q[r]][j-1]-f[i][j-1]+s[q[r]]-s[i])*(q[r-1]-q[r]))r--;
    			q[++r]=i;
    		}
    	}
    	for(int i=1;i<=p;i++)qwq=min(qwq,f[m][i]);
    	printf("%lld\n",qwq);
    	return 0;
    }
    

  • 相关阅读:
    __weak&__block&__unsafe__unretain
    Unable to convert MySQL date/time value to System.DateTime 错误
    做最好的自己,人生十件事(事业,人生,情感)
    52张扑克牌的Suit(花色)和Rank(牌面大小)排序算法
    windows service在服务器上部署时的问题
    "Unable to compile template. Check the Errors list for details" 问题解决办法
    Javascript中的一些自有方法
    winform中的webbrowser里面操作html代码问题
    Javascript,Jquery实现页面图片预加载百分比展现
    【delphi XE 】 Margin属性 转
  • 原文地址:https://www.cnblogs.com/Troverld/p/14596914.html
Copyright © 2011-2022 走看看