303. 运输小猫 - AcWing题库

是农场主,他养了 只猫,雇了 位饲养员。

农场中有一条笔直的路,路边有 座山,从 编号。

座山与第 座山之间的距离为

饲养员都住在 号山。

有一天,猫出去玩。

只猫去 号山玩,玩到时刻 停止,然后在原地等饲养员来接。

饲养员们必须回收所有的猫。

每个饲养员沿着路从 号山走到 号山,把各座山上已经在等待的猫全部接走。

饲养员在路上行走需要时间,速度为 米/单位时间。

饲养员在每座山上接猫的时间可以忽略,可以携带的猫的数量为无穷大。

例如有两座相距为 的山,一只猫在 号山玩,玩到时刻 开始等待。

如果饲养员从 号山在时刻 出发,那么他可以接到猫,猫的等待时间为

而如果他于时刻 出发,那么他将于时刻 经过 号山,不能接到当时仍在玩的猫。

你的任务是规划每个饲养员从 号山出发的时间,使得所有猫等待时间的总和尽量小。

饲养员出发的时间可以为负。

输入格式

第一行包含三个整数

第二行包含 个整数,

接下来 行,每行包含两个整数

输出格式

输出一个整数,表示所有猫等待时间的总和的最小值。

数据范围

, , , ,

输入样例:

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;
}