Cats Transport
题解
很水的一道斜率优化呀
首先因为每只猫玩的位置与玩的时间是一定的,故可以将其转化为铲*官带走猫所需要的出发时间。
于是,我们将其排序后得到的单调不下降序列上截取个点,当做其的出发时间。
令为铲*官已有
人出发,第
人在刚好可以带走第
只猫的时间出发时猫们最小的出发时间,容易得到转移方程式:
。用前缀和将
表示出来,
。
时间复杂度,明显会T,思考优化。
当对于点,点
比点
更优时
故
又转化成了熟悉的斜率优化的格式,于是,用单调队列维护斜率即可。
时间复杂度(有个排序),可以过。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
typedef long long LL;
typedef pair<int,int> pii;
const LL mo=1e9+7;
const LL INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
LL n,m,p,d[MAXN],t[MAXN],dp[105][MAXN],sum[MAXN];
LL head[105],tail[105],q[105][MAXN];
double slope(int t,LL k,LL j){return 1.0*(dp[t][k]-dp[t][j]+sum[k]-sum[j])/(k-j);}
signed main(){
scanf("%lld %lld %lld\n",&n,&m,&p);
for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
for(int i=1;i<=m;i++){
int pos;scanf("%lld %lld",&pos,&t[i]);
t[i]=t[i]-d[pos];
}
if(p>=m){puts("0");return 0;}
sort(t+1,t+m+1);dp[0][0]=0;
for(int i=1;i<=m;i++)sum[i]=sum[i-1]+t[i];
for(int j=1;j<=m;j++)
for(int i=1;i<=min(1ll*j,p);i++){
while(head[i-1]+1<tail[i-1]&&slope(i-1,q[i-1][head[i-1]],q[i-1][head[i-1]+1])<=t[j])head[i-1]++;
int k=q[i-1][head[i-1]];dp[i][j]=dp[i-1][k]+1ll*t[j]*(j-k)-sum[j]+sum[k];
//printf("%d %d %d:%lld\n",i,j,q[head],dp[i&1][j]);
while(head[i]+1<tail[i]&&slope(i,q[i][tail[i]-2],q[i][tail[i]-1])>slope(i,q[i][tail[i]-1],j))tail[i]--;
q[i][tail[i]++]=j;
/*for(int k=0;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+(j-k)*t[j]-(sum[j]-sum[k]));*/
}
printf("%lld",dp[p][m]);
return 0;
}