【队内练习赛】OMG爱吃鸡 【dp递推】【思维题】【好题】
OMG爱吃鸡
Time Limit: 3000ms
Memory Limit: 65536KB
Description
OMG 爱吃鸡。他要在n天里每天吃一只鸡。每天要吃的鸡分别有Ai的美味度。 但是他是一个有品位的人,他要求每天吃的鸡的美味度都不低于前一天的美味度。(第一天任意) 所以膜法师GG需要修改(增加或者降低或者不变)每只鸡的美味度,来满♂足他。现要求修改的美味度总和最少,求总和。
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; }
Fighting~