POJ 3666 Making the Grade(二维DP)

时间:2022-11-30 06:46:12

题目链接:http://poj.org/problem?id=3666

题目大意:
给出长度为n的整数数列,每次可以将一个数加1或者减1,最少要多少次可以将其变成单调不降或者单调不增(题目BUG,只能求单调不降).
解题思路:
有一个结论,每次将数字X改成Y时,Y一定是出现过的,所以可以用哈希减小数据范围。
因为只用求单调不降,所以设dp[i][j]表示将1~i变为不降序列,且把第i个数改为第Hash[j]的最小花费 .
可以得到状态转移方程dp[i][j]=min(dp[i-1][1~j])+abs(Hash[j]-a[i])

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N=2e3+; LL a[N],dp[N][N],Hash[N];//dp[i][j]表示将1~i变为不降序列,且把第i个数改为第Hash[j]的最小花费 LL Abs(LL a){
return a>=?a:-a;
} int main(){
int n;
cin>>n;
for(int i=;i<=n;i++){
cin>>a[i];
Hash[i]=a[i];
}
sort(Hash+,Hash++n);
int cnt=unique(Hash+,Hash++n)-Hash; for(int j=;j<cnt;j++){
dp[][j]=Abs(Hash[j]-a[]);
}
for(int i=;i<=n;i++){
LL tmp=1e18;
for(int j=;j<cnt;j++){
tmp=min(tmp,dp[i-][j]);
dp[i][j]=Abs(Hash[j]-a[i]);
dp[i][j]+=tmp;
}
}
LL ans=1e18;
for(int j=;j<cnt;j++)
ans=min(ans,dp[n][j]);
cout<<ans<<endl;
return ;
}