程式設計
online judge: TCIRC
link: https://judge.tcirc.tw/ShowProblem?problemid=d038
有
第一行是
4 5
-1 0
1 0
-2 -3
2 -3
4 -5 -1 0 2
15
範例的圖
先找到提示中,組成紅色線的那些線,並把其他不相關的線刪掉,再記錄紅色線轉彎地方的點的
維護一個stack,裡面的線皆是當前的解,依斜率由小到大加入,如果即將加入的線,比他前面的線還好時,就可以把前面的線pop掉。
數字代表放入stack的順序,令
當直線3沒有比直線2好的時候,如左圖,
而直線3比直線2好的時候,如右圖,
所以得到一個結論,當
過濾掉一些不會用到的線之後,用一個陣列去紀錄線與線之間的
#include<iostream>
#include<algorithm>
#define a first
#define b second
#define x first
#define y second
#define MAX_N 100020
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
pll line[MAX_N];
pll dq[MAX_N]; // actually it's a stack
ll C[MAX_N];
double pos[MAX_N];
int lf = 0, rt = 0;
pdd getPoint(pll p1, pll p2) {
pdd res;
double a1 = p1.a, b1 = p1.b;
double a2 = p2.a, b2 = p2.b;
res.x = (b2 - b1) / (a1 - a2);
res.y = (a2*b1 - a1*b2) / (a2 - a1);
return res;
}
bool discardLast(int idx) {
if (line[idx].a == dq[rt-1].a) {
return true;
}
pdd p = getPoint(line[idx], dq[rt-1]);
pdd lp = getPoint(dq[rt-1], dq[rt-2]);
if (p.x > lp.x) {
return false;
} else {
return true;
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int N, M;
cin >> N >> M;
for (int i = 0;i < N;i++) {
cin >> line[i].a >> line[i].b;
}
for (int i = 0;i < M;i++) {
cin >> C[i];
}
sort(line, line+N);
sort(C, C+M);
for (int i = 0;i < N;i++) {
while (rt - lf >= 2 && discardLast(i)) {
--rt;
}
dq[rt++] = line[i];
}
for (int i = lf, idx = 0;i <= rt-2;i++, idx++) {
pdd p = getPoint(dq[i], dq[i+1]);
pos[idx] = p.x;
}
ll ans = 0;
int idx = 0;
for (int i = 0;i < M;i++) {
while (idx < rt-lf-1 && C[i] > pos[idx]) {
idx++;
}
pll p = dq[lf+idx];
ans += (p.a*C[i] + p.b);
}
cout << ans << '\n';
return 0;
}