luogu2893 [USACO08FEB]Making the Grade G

題意:農夫約翰想改造一條路,原來的路的每一段海拔是A_i,修理後是B_i,花費|A_i – B_i|。我們要求修好的路是單調不升或者單調不降的。求最小花費。

貪心:以單調不降爲例,把元素從左到右推進大根堆中,若小於堆頂,則加上堆頂和當前值的差並把堆頂的數pop插入當前的數,複雜度nlogn

假設塞到第i個了,前面是一個合法的遞增序列,堆頂爲y,當前爲x且x<y

這時候我們花掉了y-x塊錢進行調整,考慮我們調整可以得到哪些結果

二元組(x,x),(x+1,x+1),..(y-1,y-1),(y,y)(x,x),(x+1,x+1),..(y−1,y−1),(y,y)都是可能的結果,雖然有的結果可能不合法,但一定存在合法的結果

我們儘可能想讓當前的數值小,所以我們儘可能會選擇小的合法結果

這時候我們發現,如果堆頂在後面被更新了,我們的合法結果的選擇集合就變了

如果我們直接把最小的可能不合法的結果放進堆,那麼當比它大的元素都被砍掉後(也就是它成了堆頂),它就變得合法了

#include<bits/stdc++.h>
using namespace std;
int n;
int a[2005];
int main()
{
	cin >> n;
	priority_queue<int>q;
	priority_queue<int, vector<int>, greater<int>>q1;
	int ans = 0, ans1=0;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		q.push(a[i]);
		if (a[i] < q.top())
		{
			ans += q.top() - a[i];
			q.pop();
			q.push(a[i]);
		}
	}
	for (int i = 1; i <= n; i++)
	{
		q1.push(a[i]);
		if (a[i] > q1.top())
		{
			ans1 += a[i] - q1.top();
			q1.pop();
			q1.push(a[i]);
		}
	}
	//cout << ans << " " << ans1 << endl;
	cout << min(ans, ans1) << endl;
}

動態規劃:f[i][j]表示把前i個數變爲單調不降且第i個數爲b[j](b[i]表示第i大的數,此處是離散化處理)的最小花費,則f[i]][j]=min(f[i-1][k]+abs(a[i]-b[j]))(1=<k<=j),此時複雜度n^3,考慮將f[i][j]定義爲前i個數變爲單調不降且第i個數<=b[j]的最小花費,可以變爲n^2

#include<bits/stdc++.h>
using namespace std;
int n, m, ans, a[2001], t[2001], b[2001];
int f[2001][2001], minf[2001][2001];
bool cmp(int a, int b)
{
	return a > b;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i]);
		t[i] = a[i];
	}
	sort(t + 1, t + n + 1);
	int now = -1;
	for (int i = 1; i <= n; i++)
		if (now != t[i])
			b[++m] = t[i], now = t[i];
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			f[i][j] = minf[i - 1][j] + abs(a[i] - b[j]);
			if (j == 1)
				minf[i][j] = f[i][j];
			else
				minf[i][j] = min(minf[i][j - 1], f[i][j]);
		}
	ans = minf[n][m];
	memset(f, 0, sizeof(f));
	memset(minf, 0, sizeof(minf));
	sort(b + 1, b + m + 1, cmp);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			f[i][j] = minf[i - 1][j] + abs(a[i] - b[j]);
			if (j == 1)
				minf[i][j] = f[i][j];
			else
				minf[i][j] = min(minf[i][j - 1], f[i][j]);
		}
	ans = min(ans, minf[n][m]);
	printf("%d", ans);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章