E - Active Infants (贪心&DP)

题目传送门

此题贪心的思路是优先对较大的数往两边放。可以有两种方法:1.递归+类似区间DP形式 2.设dp[ i ][ j ]表示往左放的个数和往右放的个数从小到大递推。具体看代码。

法1:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+5;
vector<pair<ll,ll> >v(N);//vector对pair排序时按'键'排序 即第一元素first 
ll dp[N][N];
int n;
ll fun(int l,int r){
	if(l>r) return 0;
	if(dp[l][r]) return dp[l][r];
	int i=n-(r-l+1);//当前要放入的数的下标 
	return dp[l][r]=max(fun(l,r-1)+v[i].first*(r-v[i].second),fun(l+1,r)+v[i].first*(v[i].second-l));//放两端取最大 
}
int main(){
	scanf("%d",&n);
	for(int i=0,x;i<n;i++)
		scanf("%d",&x),v.push_back({x,i});
	sort(v.rbegin(),v.rend());//贪心从大到小排 
	fun(0,n-1);
	printf("%lld\n",dp[0][n-1]);
	return 0;
}

法2:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+5;
ll dp[N][N];
struct p{
	int x,id;
	bool operator<(const p&a)const{
		return x>a.x; 
	}
}a[N];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].x),a[i].id=i;
	sort(a+1,a+n+1);//从大到小排序 
	for(int k=1;k<=n;k++)//对第k个元素进行放置(前k-1个元素所有情况都已知) 
		for(int i=0;i<k;i++)//遍历前k-1元素的所有情况. i为往左放置的个数. 
		{
			int j=k-1-i;//前k-1元素往右放置的个数. 
			dp[i+1][j]=max(dp[i+1][j],dp[i][j]+(ll)a[k].x*(a[k].id-(i+1)));//往左放 
			dp[i][j+1]=max(dp[i][j+1],dp[i][j]+(ll)a[k].x*(n-j-a[k].id));//往右放 
		}
	ll ans=0;
	for(int i=0;i<=n;i++) ans=max(ans,dp[i][n-i]);//取最大值. 
	printf("%lld\n",ans);
	return 0;
}