洛谷CF311B Cats Transport(DP)(斜率优化)

题目

洛谷CF311B Cats Transport

题解

斜率优化
1-i的距离为D[i],即D[i]=\sum d[i]
先转换一下模型。对于第i只猫,饲养员要在t[i]-D[i]之后出发,才能把它带回家。
故我们设数组A[i]=D[i]-t[i],问题就转换成了在A数组中分成p组,每组(l,r)的代价是\sum_{l<=i<=r}^{ }A[r]-A[i]
为了方便操作,对A进行递增排序。同时,记录其前缀和S。

在此基础上,设f[i][j]表示出动j个饲养员带走前i只猫的最小等待时间。
转移方程:


f[i][j]= \min_{0<=k<j} \left\{ f[i-1][k]+ S[j]-S[k]-A[j]*(j-k) \right\}


在上述方程中,把i看成定量,j看成状态变量,k看成决策变量。把仅与k有关的放在等号左边,仅与j有关的和与j和k都有关的放在等号右边。去掉min函数,并移项,得:


f[i-1][k]-S[k]=A[j]*k+f[i][j]-A[j]*j+S[j]


对于上面这个式子,可以理解成在一个以k为横坐标,f[i-1][k]-S[k]为纵坐标的坐标系上,有一条斜率为A[j]的直线,截距为f[i][j]-A[j]*j+S[j]。决策点坐标为\left\(k,f[i-1][k]-S[k]\right\)
我们可以让横坐标k递增枚举,同时又有斜率A[j]递增,可以直接用最模板的斜率优化解决。
因为要最小化f[i][j],所以截距要最小化,维护一个下凸壳。

代码

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll inf=4557430888798830399;
const int maxn=2e5+10,maxm=1e5+10,maxp=110;

int n,m,p;
ll d[maxn],s[maxn];
ll a[maxm];

ll f[maxp][maxm],g[maxm];

int q[maxm];int l,r;

int main()
{
    cin>>n>>m>>p;
    for(int i=2;i<=n;i++)
    {
        cin>>d[i];
        d[i]+=d[i-1];
    }
    for(int i=1;i<=m;i++)
    {
        int h,t;
        cin>>h>>t;
        a[i]=t-d[h];
    }
    sort(a+1,a+m+1);
    for(int i=1;i<=m;i++) s[i]=s[i-1]+a[i];
    
    memset(f,63,sizeof(f));f[0][0]=0;
    for(int i=1;i<=p;i++)
    {
        for(int j=1;j<=m;j++) g[j]=f[i-1][j]+s[j];//g表示纵坐标
        l=r=1;q[1]=0;
        for(int j=1;j<=m;j++)
        {
            while(l=inf) continue;
            while(l= (g[j]-g[q[r]]) * (q[r]-q[r-1])) r--;
            q[++r]=j;
        }
    }
    printf("%lld\n",f[p][m]);
    return 0;
}

 

你可能感兴趣的:(刷题之路,单调队列,斜率优化,动态规划DP,《算法竞赛进阶指南》刷书之旅)