ABC163 E - Active Infants

Question

将一个数组重新排序,每个元素的收益为 a [ i ] × l e n m o v e a[i]\times len_{move} a[i]×lenmove,求排序后的最大收益。

Solution

DP
容易想到一个大的值无非放到左边和右边,哪边增加的多放到哪边,但是可能存在放到两边值一样的情况,那么这个时候的选择会影响到之后的选择,所以贪心是不对滴,这里要用到DP。
先排个序,从大到小,然后每次先选未选过的最大的,枚举其在左右的两种情况。
d p [ L ] [ R ] = m a x ( d p [ L + 1 ] [ R ] + a n o w × p o s n o w L , d p [ L ] [ R 1 ] + a n o w × p o s n o w R ) dp[L][R] = max(dp[L+1][R] + a_{now} \times \left | pos_{now} - L \right |,dp[L][R-1]+a_{now} \times \left | pos_{now} - R\right | ) dp[L][R]=max(dp[L+1][R]+anow×posnowL,dp[L][R1]+anow×posnowR)
这里看到有两种写法,一种是记忆化搜索,一种是DP,其实感觉记忆化搜索和DP实际上一回事,思想都是不重复找已经找到的量。

Code

记忆化搜索

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;
const int N = 2e3 + 5;

ll n,dp[N][N];
vector<pair<ll,int> >V(n);

ll DP(int L,int R){
	if(R<L) return 0;
	if(dp[L][R]!=-1) return dp[L][R];
	int i=L+n-1-R;
	return dp[L][R]=max(V[i].first*abs(V[i].second-L)+DP(L+1,R),V[i].first*abs(V[i].second-R)+DP(L,R-1));
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=0;i<n;i++){int x;cin>>x; V.push_back({x,i});}
	sort(V.rbegin(),V.rend());
	memset(dp,-1,sizeof(dp));
	cout<<DP(0,n-1);
	return 0;
}

DP

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;
const int N = 2000 + 5;

int n;
pair<ll,int> a[N];
ll f[N][N];

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i].first;
		a[i].second=i;
	}
	sort(a,a+n,greater<pair<int,int> >());
	for(int i=0;i<n;i++){
		for(int j=0;j<=i;j++){
			int k=i-j;
			f[j+1][k]=max(f[j+1][k],f[j][k]+a[i].first*abs(a[i].second-j));
			f[j][k+1]=max(f[j][k+1],f[j][k]+a[i].first*abs(n-k-1-a[i].second));
		}
	}
	ll ans=0;
	for(int i=0;i<=n;i++) ans=max(ans,f[i][n-i]);
	cout<<ans;
	return 0;
}