《算法竞赛进阶指南》0x5A斜率优化 AcWing303运输小猫

题目链接:https://www.acwing.com/problem/content/305/

题目给出n坐山,m只小猫,每只小猫到山Hi去玩Ti小时,两座山之间的距离已知,现在有p个饲养者去带这些猫回家,他们只能在猫玩了Ti小时之后才能接到她,小猫玩完就会等待来接,问这些小猫的总的等待时间最少是多少。

通过计算可以知道对于每个猫的最早接的时间,也可以知道如果饲养者从t开始取接她他将会等待多少时间,现在将等待时间排序,容易知道每个饲养员接的猫在排序之后是连续的片段。

所以就和任务分配很像,通过方程转移,发现是一个斜率优化单调队列问题,维护决策集合k,保证决策集合中的斜率是单调上升的即可。

这道题的难点在于状态的转移。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100010;
ll S[N],A[N];
int sumd[N];
int n,m,p;
ll f[105][N];
ll g[N];//保存函数值 
int q[N];
int main(){
    cin>>n>>m>>p;
    ll x,y;
    for(int i=2;i<=n;i++){
        scanf("%lld",&x);
        sumd[i]=sumd[i-1]+x;
    }
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&x,&y); 
        A[i]=y-sumd[x];//最早的出发时间 
    }
    sort(A+1,A+m+1);
    for(int i=1;i<=m;i++)S[i]=S[i-1]+A[i];
    
    memset(f,0x3f,sizeof f);
    f[0][0]=0;
    
    for(int i=1;i<=p;i++){
        int l=1,r=1;
        q[1]=0;
        for(int j=0;j<=m;j++)g[j]=f[i-1][j]+S[j];
        for(int j=0;j<=m;j++){
            while(l<r && g[q[l+1]]-g[q[l]]<=(q[l+1]-q[l])*A[j])l++;
            f[i][j]=min(f[i][j],f[i-1][q[l]]+A[j]*(j-q[l])-(S[j]-S[q[l]]));
            while(l<r && (g[j]-g[q[r]])*(q[r]-q[r-1])
                        <=(g[q[r]]-g[q[r-1]])*(j-q[r]))r--;
            q[++r]=j;
        }    
    }
    cout<<f[p][m]<<endl;
    
    return 0;
}

 

posted @ 2020-08-04 12:16  WA自动机~  阅读(188)  评论(0编辑  收藏  举报