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]);
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值