【隊內練習賽】OMG愛喫雞 【dp遞推】【思維題】【好題】

 

OMG愛喫雞

Time Limit: 3000ms

Memory Limit: 65536KB

Description

  OMG 愛喫雞。他要在n天裏每天喫一隻雞。每天要喫的雞分別有Ai的美味度。  但是他是一個有品位的人,他要求每天喫的雞的美味度都不低於前一天的美味度。(第一天任意)  所以GG需要修改(增加或者降低或者不變)每隻雞的美味度,來滿足他。現要求修改的美味度總和最少,求總和。

Input

  多組case,每組case第一行輸入一個n,第二行輸入n個數( 1<=n <= 2000, 數的範圍[0,1e9])

Output

  輸出修改的美味度總和

Sample Input

7
1 3 2 4 5 3 9

Sample Output

3

 

 

 

dp[i][j]表示前i爲,最後一位爲j的情況,因爲數字只有2000個,且最後一位修改的值一定2000個數字中出現過的一個,枚舉最後一位數字,dp遞推一下即可

注意:遞推時用minv[i][j]表示前i個以j結尾的最小的值是多少,這樣遞推時只需要o(1)便可只前面最優的值,直接遞推即可(遞推和優化),這樣o(n^2)即可解。

ps(最後結果最大值會超過0x3f3f3f3f,INF設成0x3f3f3f3f會WA)

 

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ms(x,y) memset(x,y,sizeof(x))
using namespace std;

typedef long long ll;

const int mod = 998244353;
const int maxn = 2010;

int a[maxn], b[maxn], p[maxn];
ll minv[maxn][maxn];
ll dp[maxn][maxn];

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int n;
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]), b[i] = a[i];
		sort(b + 1, b + 1 + n);
		int tol = 2;
		p[1] = b[1];
		for (int i = 2; i <= n; i++)
		{
			if (b[i] != b[i - 1])
			{
				p[tol++] = b[i];
			}
		}
		ms(dp, INF);
		//ms(dp[0], 0);
		ms(minv, INF);
		ms(minv[0], 0);
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j < tol; j++)
			{
				dp[i][j] = minv[i - 1][j] + abs(p[j] - a[i]);
				minv[i][j] = min(minv[i][j - 1], dp[i][j]);
			}
		}
		ll ans = dp[n][1];
		for (int i = 1; i < tol; i++)
		{
			ans = min(ans, dp[n][i]);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

 

 

 

 

 

 

 

 

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