http://poj.org/problem?id=3666
题意: 给出一个序列, 问将这个序列改成不上升/不下降序列的最小代价是多少.代价是每个值修改前后差的绝对值之和.
思路: 离散化后dp.
离散化的正确性不会证...
代码只有不下降序列的...水过去了...(✿◡‿◡)
dp[i][j]表示前i个数中, 最后一个数是j时的最小代价.
递推式: dp[i][j]=min(dp[i-1][0->j])+abs(j-a[i]) 每个状态由前一位的最大值<=j的所有状态的最小值+新增代价决定.
WA的代码:
for(int i=1; i<=n; i++) {
ll tmp=inf;
for(int j=0; j<=g(a[i]); j++) {
tmp=min(tmp,dp[i-1][j]);
dp[i][g(a[i])]=min(dp[i][g(a[i])],dp[i-1][j]);
}
for(int j=g(a[i])+1; j<m; j++) {
tmp=min(tmp,dp[i-1][j]);
dp[i][j]=min(dp[i][j],tmp+abss(v[j]-a[i]));
}
}
相当于没有考虑i位置自降身段的情况, 根本没有更新dp[i][0->a[i]]的值.
AC代码:
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=2e3+5;
const ll inf=1e18+5;
const int mod=1e9+7;
//memset(a,0x3f,sizeof(a));
ll a[M];
ll dp[M][M];
vector<ll>v;
int g(ll x) {
return lower_bound(v.begin(),v.end(),x)-v.begin();
}
ll abss(ll a) {
return a>=0?a:-a;
}
int main() {
fill(dp[0],dp[0]+M*M,inf);
int n;
scanf("%d",&n);
v.push_back(0);
for(int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());
int m=unique(v.begin(),v.end())-v.begin();
v.erase(v.begin()+m,v.end());
for(int i=0; i<m; i++) {
dp[0][i]=0;
}
for(int i=1; i<=n; i++) {
ll tmp=inf;
for(int j=0; j<m; j++) {
tmp=min(tmp,dp[i-1][j]);
dp[i][j]=min(dp[i][j],tmp+abss(v[j]-a[i]));
}
}
ll ans=inf;
for(int i=0; i<=m; i++) {
ans=min(ans,dp[n][i]);
}
printf("%lld\n",ans);
return 0;
}