版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/82835719
题目
题解
斜率优化
设的距离为,即。
先转换一下模型。对于第i只猫,饲养员要在t[i]-D[i]之后出发,才能把它带回家。
故我们设数组,问题就转换成了在A数组中分成p组,每组(l,r)的代价是。
为了方便操作,对A进行递增排序。同时,记录其前缀和S。
在此基础上,设f[i][j]表示出动j个饲养员带走前i只猫的最小等待时间。
转移方程:
在上述方程中,把i看成定量,j看成状态变量,k看成决策变量。把仅与k有关的放在等号左边,仅与j有关的和与j和k都有关的放在等号右边。去掉min函数,并移项,得:
对于上面这个式子,可以理解成在一个以为横坐标,为纵坐标的坐标系上,有一条斜率为的直线,截距为。决策点坐标为。
我们可以让横坐标k递增枚举,同时又有斜率递增,可以直接用最模板的斜率优化解决。
因为要最小化f[i][j],所以截距要最小化,维护一个下凸壳。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
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<r && g[q[l+1]]-g[q[l]] <= (q[l+1]-q[l]) * a[j]) l++;
f[i][j]=min(f[i-1][j],g[q[l]]+a[j]*(j-q[l])-s[j]);//不用加再+s[k],因为已经包含在g中了
if(g[j]>=inf) continue;
while(l<r && (g[q[r]]-g[q[r-1]]) * (j-q[r]) >= (g[j]-g[q[r]]) * (q[r]-q[r-1])) r--;
q[++r]=j;
}
}
printf("%lld\n",f[p][m]);
return 0;
}