【链接】 我是链接,点我呀:)

【题意】

在这里输入题意

【题解】

把这n个土地按照x为第一关键字、y为第二关键字。都升序排。
然后考虑一个土地xi,yi
若有一个土地的x这个去掉土地的过程可以用单调队列实现。
这样。我们会发现剩下的土地按照从1开始的顺序。
就x是升序的,且y是降序的了。
接下来,会发现我们要买的土地,肯定都是连续一段地买的。
比如,你买了第一个土地,又买了第3个土地。
那么你肯定再把第二个土地买了更优。
因为花费只取决于第一个土地的y和第3个土地的x了(y递减,x递增);
你中间不论有多少土地。花费都是一样的。
因此,买的肯定都是一段一段的。
做个DP就好。
设f[i]表示i是最后一段的**最后一段**的**最小花费**
方程是
$f[i] = min(f[j]+x_i*y_{j+1})$
加一个斜率优化就好

【错的次数】

在这里输入错的次数

【反思】

在这里输入反思

【代码】

#include <bits/stdc++.h>
#define ll long long
using namespace std; const int N = 5e4; int n, dl[N + 10], h, t;
pair <ll, ll> b[N + 10],a[N+10];
ll f[N + 10]; double ju(int x, int y)
{
double fenzi = f[y] - f[x];
double fenmu = a[x + 1].second - a[y + 1].second;
return fenzi / fenmu;
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld%lld", &b[i].first, &b[i].second);
sort(b + 1, b + 1 + n);
int nn = 0;
for (int i = 1; i <= n; i++)
{
while (nn > 0 && a[nn].second <= b[i].second) nn--;
a[++nn] = b[i];
} n = nn;
h = t = 1;
dl[1] = 0; for (int i = 1; i <= n; i++)
{
while (h < t && ju(dl[h], dl[h + 1]) < a[i].first) h++;
int j = dl[h];
f[i] = f[j] + a[i].first*a[j + 1].second;
while (h < t && ju(dl[t - 1], dl[t]) > ju(dl[t], i)) t--;
dl[++t] = i;
} printf("%lld\n", f[n]);
return 0;
}
05-11 13:52