CF 311B Cats Transport(单调队列优化DP)

题目链接:http://codeforces.com/problemset/problem/311/B

题意:有1到n共n座山。m个牛。每个牛都 在某一个山上吃草。第i个牛在时间ti时刻吃完草然后在山下等着管理员来牵走。给出相邻两座山之间的距离。已知有P个管理员。管理员从1出发依次到n将正 在等的牛牵走。注意管理员不会在山下等牛,只牵走正在等的牛。管理员的走路速度为1。假如1到2的距离为10,那么管理员2时刻从1出发,到达2的时刻为 12。合理安排每个管理员从1的出发时间使得牛的总等待时间最少?

思路:设第i个山距离第1个山的距离为 d[i],第j个牛在第i个山上,那么保存a[j]=j-d[i]。将a排序。那么问题转化为将a[1]-a[m]最多分成P组,每组的代价为这组中每个 数与最大的那个数的差的和。使得总代价最少。设s[i]=a[1]+a[2]+……a[i]。f[i][j]表示前j个分成i组的最小代价,那么显然有: f[i][j]=f[i-1][k]+(j-k)*a[j]-(s[j]-s[k])=j*a[j]+f[i-1][k]+s[k]-a[j]*k。这个 复杂度太大。我们试图化简。设两个k1,k2,满足k2>k1但是k2比k1更优,那么f[i-1] [k1]+s[k1]-a[j]*k1>=f[i-1][k2]+s[k2]-a[j]*k2。令dy(k1,k2)=(f[i-1] [k1]+s[k1])-(f[i-1][k2]+s[k2]),dx(k1,k2)=k1-k2,那么上式等价于:dy(k1,k2)>=a[j]*dx(k1,k2)。进而我们可以使用单调队列优化,复杂度为O(Pm)。

 

int n,m,P;

i64 f[2][N],s[N],b[N],a[N];

int Q[N],L,R,pre,cur;





i64 dy(int p,int q)

{

return (f[pre][p]+s[p])-(f[pre][q]+s[q]);

}



i64 dx(int p,int q)

{

    return p-q;

}





int main()

{

    RD(n,m,P);

    int i,j,k,x;

    for(i=2;i<=n;i++) RD(b[i]),b[i]+=b[i-1];

    FOR1(i,m) RD(x),RD(a[i]),a[i]-=b[x];

    sort(a+1,a+m+1);

    FOR1(i,m) s[i]=s[i-1]+a[i];

    if(P>=m)

    {

        puts("0");

        return 0;

    }

    pre=0;cur=1;

    FOR1(i,m) f[0][i]=i*a[i]-s[i];

    FOR1(k,P-1)

    {

        L=R=0; Q[0]=0;

        FOR1(i,m)

        {

            while(L<R&&dy(Q[R-1],Q[R])*dx(Q[R],i)>=dy(Q[R],i)*dx(Q[R-1],Q[R])) R--;

            Q[++R]=i;

            while(L<R&&dy(Q[L],Q[L+1])>=a[i]*dx(Q[L],Q[L+1])) L++;

            j=Q[L];

            f[cur][i]=f[pre][j]+(i-j)*a[i]-s[i]+s[j];

        }

        swap(pre,cur);

    }

    PR(f[pre][m]);

}

 

 

 

你可能感兴趣的:(port)