一、题目
二、解法
首先设每个猫需要铲屎官出发的时间为 t [ i ] t[i] t[i](可能为负数),铲屎官没迟出发一分钟这只猫就要多等一分钟,先按 t t t从小到大排序,求出他的前缀和 s [ i ] s[i] s[i]
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]考虑到第
i
i
i个铲屎官,已经接走前
j
j
j只猫的最小等待时间之和,转移:
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
k
]
+
t
[
j
]
×
(
j
−
k
)
−
(
s
[
j
]
−
s
[
k
]
)
dp[i][j]=dp[i-1][k]+t[j]\times(j-k)-(s[j]-s[k])
dp[i][j]=dp[i−1][k]+t[j]×(j−k)−(s[j]−s[k])如果你结合最开始的说明就不难理解这个转移了,时间复杂度
O
(
p
m
)
O(pm)
O(pm)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
const int M = 100005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,p,ls,q[M],d[M],s[M],T[M],dp[105][M];
double slope(int x,int y)
{
return 1.0*(dp[ls][x]+s[x]-dp[ls][y]-s[y])/(x-y);
}
signed main()
{
n=read();m=read();p=read();
for(int i=2;i<=n;i++)
d[i]=read()+d[i-1];
for(int i=1;i<=m;i++)
{
int h=read();
T[i]=read()-d[h];
}
sort(T+1,T+1+m);
for(int i=1;i<=m;i++)
s[i]=s[i-1]+T[i];
memset(dp,0x3f,sizeof dp);
dp[0][0]=0;
for(int i=1;i<=p;i++)
{
int h=0,t=0;q[0]=0;ls=i-1;
for(int j=1;j<=m;j++)
{
while(h<t && slope(q[h],q[h+1])<T[j]) h++;
dp[i][j]=dp[ls][q[h]]+T[j]*(j-q[h])-s[j]+s[q[h]];
while(h<t && slope(q[t],q[t-1])>slope(j,q[t])) t--;
q[++t]=j;
}
}
printf("%lld\n",dp[p][m]);
}