小 是农场主,他养了 只猫,雇了 位饲养员。
农场中有一条笔直的路,路边有 座山,从 到 编号。
第 座山与第 座山之间的距离为 。
饲养员都住在 号山。
有一天,猫出去玩。
第 只猫去 号山玩,玩到时刻 停止,然后在原地等饲养员来接。
饲养员们必须回收所有的猫。
每个饲养员沿着路从 号山走到 号山,把各座山上已经在等待的猫全部接走。
饲养员在路上行走需要时间,速度为 米/单位时间。
饲养员在每座山上接猫的时间可以忽略,可以携带的猫的数量为无穷大。
例如有两座相距为 的山,一只猫在 号山玩,玩到时刻 开始等待。
如果饲养员从 号山在时刻 或 出发,那么他可以接到猫,猫的等待时间为 或 。
而如果他于时刻 出发,那么他将于时刻 经过 号山,不能接到当时仍在玩的猫。
你的任务是规划每个饲养员从 号山出发的时间,使得所有猫等待时间的总和尽量小。
饲养员出发的时间可以为负。
输入格式
第一行包含三个整数 。
第二行包含 个整数, 。
接下来 行,每行包含两个整数 和 。
输出格式
输出一个整数,表示所有猫等待时间的总和的最小值。
数据范围
, , , ,
输入样例:
4 6 2
1 3 5
1 0
2 1
4 9
1 10
2 10
3 12
输出样例:
3
思路
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int n,m,p;
LL a[N]; // 最小等待时间
LL d[N], s[N];
LL f[110][N];
int q[N];
LL get_y(int j, int k)
{
return f[j - 1][k] + s[k];
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
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++)
{
LL 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, 0x3f, sizeof f);
for(int i = 0; i <= p; i++) f[i][0] = 0;
for(int j = 1; j <= p; j++)
{
int hh = 0, tt = 0;
q[0] = 0;
for(int i = 1; i <= m; i++)
{
while(hh < tt && (get_y(j,q[hh + 1]) - get_y(j,q[hh])) <= a[i] * (q[hh + 1] - q[hh])) hh++;
int k = q[hh];
f[j][i] = f[j - 1][k] + s[k] - a[i]*k + a[i]*i - s[i];
while(hh < tt && (get_y(j, q[tt]) - get_y(j, q[tt - 1])) * (i - q[tt])
>= (get_y(j, i) - get_y(j, q[tt])) * (q[tt] - q[tt - 1])) tt--;
q[++ tt] = i;
}
}
cout << f[p][m] << endl;
return 0;
}