【S - Making the Grade】

80 篇文章 0 订阅
80 篇文章 0 订阅

思路:

  • 动态规划+离散化
  • 数据范围过大,需要离散化:A【】是原数组,U【】是去重数组,dp【】是代价。
  • 心路历程:
    1. 最核心的:每改一个数必定不会改成一个在全数组中从未出现过的新数。dp 依据)
    2. dp[i][j] 代表前 i 个数符合某规则并且将最后一个元素改成数字 j 所付出的总代价,得到一个 TLE
    3. 使用滚动数组,将 dp[maxn][maxn] 改成一维,仍然 TLE
    4. 使用变量 PRESUM,降低时间复杂度。
  • 注意:
    1. 两种规则(不升\不降)只需要一次 reverse
    2. 用到的STL:unique、reserve、min_element 。

代码:

  • 朴素dp:TLE
//TLE


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> 
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 2005;

int N;
int M;
int ans;
int A[maxn];
int U[maxn];
int dp[maxn][maxn]; 

int SOLVE(){
	for(int i=0;i<M;i++)
		dp[0][i] = abs(A[0] - U[i]);
	for(int i=1;i<N;i++){
		for(int j=0;j<M;j++){
			int MIN = INF;
			for(int k=0;k<=j;k++)//前面的(i-1)个数优化到全部(x)于U[j]的非(x)序列 的代价 
				MIN = min(MIN , dp[i-1][k]);
			dp[i][j] = MIN + abs(A[i] - U[j]);
		}
	}
	return *min_element(dp[N-1] , dp[N-1] + M);
}

int main(){
	cin>>N;
	for(int i=0;i<N;i++)
		cin>>A[i] , U[i] = A[i];
	sort(U , U + N);
	M = unique(U , U + N) - U;
	ans = INF;
	ans = min(ans , SOLVE());
	reverse(U , U + N);
	ans = min(ans , SOLVE());
	cout<<ans<<endl;
	return 0;
}
  • 滚动数组:TLE
//TLE


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> 
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 2005;

int N;
int M;
int ans;
int A[maxn];
int U[maxn];
int dp[maxn]; 

int SOLVE(){
	memset(dp , 0 , sizeof(dp));
	for(int i=0;i<N;i++){
		for(int j=M-1;j>=0;j--){
			//注意需要改成倒序
			int MIN = INF;
			for(int k=0;k<=j;k++)//前面的(i-1)个数优化到全部(x)于U[j]的非(x)序列 的代价
				MIN = min(MIN , dp[k]);
			dp[j] = MIN + abs(A[i] - U[j]);
		}
	}
	return *min_element(dp , dp + M);
}

int main(){
	cin>>N;
	for(int i=0;i<N;i++)
		cin>>A[i] , U[i] = A[i];
	sort(U , U + N);
	M = unique(U , U + N) - U;
	ans = INF;
	ans = min(ans , SOLVE());
	reverse(U , U + N);
	ans = min(ans , SOLVE());
	cout<<ans<<endl;
	return 0;
}
  • PRESUM:79ms 748kB
//79ms		748kB


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> 
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 2005;

int N;
int M;
int ans;
int A[maxn];
int U[maxn];
int dp[maxn]; 

int SOLVE(){
	memset(dp , 0 , sizeof(dp));
	for(int i=0;i<N;i++){
		int PRESUM = INF;
		for(int j=0;j<M;j++){
			PRESUM = min(PRESUM , dp[j]);
			dp[j] = PRESUM + abs(A[i] - U[j]);
		}
	}
	return *min_element(dp , dp + M);
}

int main(){
	cin>>N;
	for(int i=0;i<N;i++)
		cin>>A[i] , U[i] = A[i];
	sort(U , U + N);
	M = unique(U , U + N) - U;
	ans = INF;
	ans = min(ans , SOLVE());
	reverse(U , U + N);
	ans = min(ans , SOLVE());
	cout<<ans<<endl;
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值