45 lines
1.7 KiB
C++
45 lines
1.7 KiB
C++
#include <bits/stdc++.h>
|
||
|
||
using namespace std;
|
||
typedef long long LL;
|
||
const int N = 100010;
|
||
const int P = 110;
|
||
int n, m;
|
||
int p;
|
||
int q[N];
|
||
|
||
LL d[N], t[N];
|
||
LL a[N], s[N];
|
||
LL f[P][N];
|
||
int h;
|
||
|
||
int main() {
|
||
cin >> n >> m >> p;
|
||
|
||
for (int i = 2; i <= n; i++) cin >> d[i], d[i] += d[i - 1]; // 从2开始
|
||
for (int i = 1; i <= m; i++) cin >> h >> t[i], a[i] = t[i] - d[h], s[i] = s[i - 1] + a[i];
|
||
sort(a + 1, a + m + 1); // 由小到大排序,m只小猫
|
||
|
||
// dp初始
|
||
memset(f, 0x3f, sizeof f);
|
||
for (int i = 0; i <= p; i++) f[i][0] = 0; // 出动i个饲养员,接0只小猫,等待0。将DP TABLE第一列修改为0
|
||
|
||
for (int i = 1; i <= p; i++) { // 饲养员
|
||
int hh = 0, tt = 0; // 哨兵
|
||
for (int j = 1; j <= m; j++) { // 遍历小猫
|
||
// 凸包的斜率单调上升,并且,直线的斜率也是单调上升
|
||
// 准备在下凸壳中找到第一个斜率大于k的直线,小于k的全部剔除
|
||
while (hh < tt && (f[i - 1][q[hh + 1]] + s[q[hh + 1]] - f[i - 1][q[hh]] - s[q[hh]]) <= a[j] * (q[hh + 1] - q[hh]))
|
||
hh++;
|
||
// 推出的公式
|
||
f[i][j] = f[i - 1][q[hh]] + a[j] * (j - q[hh]) - (s[j] - s[q[hh]]);
|
||
// 维护下凸壳 [下面是 k=(y1-y2)/(x1-x)的PK,大的干掉。同时,为了避免除法,采用了十字相乘法变形]
|
||
while (hh < tt && (f[i - 1][j] + s[j] - f[i - 1][q[tt]] - s[q[tt]]) * (q[tt] - q[tt - 1]) <= (f[i - 1][q[tt]] + s[q[tt]] - f[i - 1][q[tt - 1]] - s[q[tt - 1]]) * (j - q[tt]))
|
||
tt--;
|
||
// 加入
|
||
q[++tt] = j;
|
||
}
|
||
}
|
||
cout << f[p][m] << endl;
|
||
return 0;
|
||
} |