1. 程式人生 > 實用技巧 >HDU-1300 Pearls(斜率DP)

HDU-1300 Pearls(斜率DP)

分析:假設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;
}