CF311B题解
题解思路:
转化题意:
我们先求一下从第一座山到以后的每一座山的距离先求出来,也就是对
那么现在的
一个饲养员走到一个猫的山开始的时间为
那么若
那么这只小猫的等待时间为:
那么我们用
那么
那么我们把小猫的
那么饲养员出发的时候,每一次饲养员每次都要接走一批的小猫。
若一个饲养员要接走前
那么前
其中
那么就相当于有
这样的话就转化成了和这道题类似了。
然后我们用斜率优化DP来做就可以了。
解法:
那么我们设
状态转移方程:
我们把
那么和
整理一下:
因为我们对
那么
那么
时间复杂度为
十年OI一场空,不开long long见祖宗!
AC CODE
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 100010 , M = 100010 , P = 110;
int n , m , p;
ll d[N] , t[N] , a[N] , s[N];
ll f[P][M];
int q[M];
ll get_y(int k , int j) {
return f[j - 1][k] + s[k];
}
int main(){
scanf ("%d%d%d" , &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 h;
scanf ("%d%lld" , &h , &t[i]);
a[i] = t[i] - d[h];//a数组
}
sort (a + 1 , a + 1 + m);//排序
for (int i = 1; i <= m; ++ i) s[i] += s[i - 1] + a[i];//a的前缀和
memset (f , 0x3f , sizeof (f));
for (int i = 0; i <= p; ++ i) f[i][0] = 0;
for (int j = 1; j <= p; ++ j) {//DP
int hh = 0 , tt = 0;
q[0] = 0;
for (int i = 1; i <= m; ++ i) {
while (hh < tt && (get_y(q[hh + 1] , j) - get_y(q[hh] , j)) <= a[i] * (q[hh + 1] - q[hh])) ++ hh;
int k = q[hh];
f[j][i] = f[j - 1][k] - a[i] * k + s[k] + a[i] * i - s[i];
while (hh < tt && (get_y(q[tt] , j) - get_y(q[tt - 1] , j)) * (i - q[tt]) >= (get_y(i , j) - get_y(q[tt] , j)) * (q[tt] - q[tt - 1])) -- tt;
q[++ tt] = i;
}
}
printf ("%lld\n" , f[p][m]);
return 0;
}