1. 程式人生 > 實用技巧 >POJ3666 & AcWing273 Making the Grade

POJ3666 & AcWing273 Making the Grade

題目連結

猜一波結論:新序列的數字一定都在原序列中出現過。證明

然後常規 dp 就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2000;
int a[N+10],t[N+10];
int dp[N+10][N+10];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	memcpy(t,a,sizeof(a));
	sort(t+1,t+n+1);
	int m=unique(t+1,t+n+1)-t-1;
	memset(dp,0x3f,sizeof(dp));
	for(int i=1;i<=m;i++) dp[0][i]=0;
	for(int i=1;i<=n;i++)
	{
		int Min=0x7fffffff;
		for(int j=1;j<=m;j++)
		{
			Min=min(Min,dp[i-1][j]);
			dp[i][j]=min(dp[i][j],Min+abs(t[j]-a[i]));
		}
	}
	int ans=0x7fffffff;
	for(int i=1;i<=m;i++) ans=min(ans,dp[n][i]);

	memset(dp,0x3f,sizeof(dp));
	for(int i=1;i<=m;i++) dp[0][i]=0;
	for(int i=1;i<=n;i++)
	{
		int Min=0x7fffffff;
		for(int j=m;j;j--)
		{
			Min=min(Min,dp[i-1][j]);
			dp[i][j]=min(dp[i][j],Min+abs(t[j]-a[i]));
		}
	}
	for(int i=1;i<=m;i++) ans=min(ans,dp[n][i]);
	printf("%d",ans);
	return 0;
}