分析:假设dp[i]为购买前i种珍珠花费的最小价格,我们可以得到dp转移方程,\(dp[i] = min\{(cnt[i] - cnt[k] + 10) * p[i] + dp[k]\}(1 <= k < i)\),我们可以对方程式进行变形,\(dp[k] = p[i] * cnt[k] + dp[i] - cnt[i] * p[i] + 10 * p[i]\),假设\(dp[k]为y\),\(cnt[k]为x\),\(截距(dp[i] - cnt[i] * p[i] + 10 * p[i])为b\),那么我们可以得到\(y = p[i] * x + b\),那么斜率则为\(p[i]\),之后我们再用一般的凸包优化即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 105;
int a[N], p[N];
int dp[N];
int q[N];
int cnt[N];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int c;
scanf("%d", &c);
for (int i = 1; i <= c; ++i)
{
scanf("%d%d", &a[i], &p[i]);
}
for (int i = 1; i <= c; ++i) cnt[i] = cnt[i - 1] + a[i];
int hh = 0, tt = 0;
q[0] = 0;
for (int i = 1; i <= c; ++i)
{
while (hh < tt && (dp[q[hh + 1]] - dp[q[hh]]) <= p[i] * (cnt[q[hh + 1]] - cnt[q[hh]])) ++hh;
int k = q[hh];
dp[i] = (cnt[i] - cnt[k] + 10) * p[i] + dp[k];
while (hh < tt && (dp[q[tt]] - dp[q[tt - 1]]) * (cnt[i] - cnt[q[tt]]) >= (dp[i] - dp[q[tt]]) * (cnt[q[tt]] - cnt[q[tt - 1]])) --tt;
q[++tt] = i;
}
printf("%d\n", dp[c]);
}
return 0;
}