C. The Sports Festival

Codeforces Round #715 (Div. 2)

C. The Sports Festival

题目:给你一个数组 a i ai ai,定义 d i = m a x ( a 1 , a 2.. , a i ) − m i n ( a 1 , a 2... , a i ) . di=max(a1,a2..,ai)-min(a1,a2...,ai). di=max(a1,a2..,ai)min(a1,a2...,ai).,让你最小化 ∑ 1 n d i \sum_1^ndi 1ndi.
你可以对数组上的元素任意地安排它的位置.
思路:先不考虑如何去安排,想像一下如何求出这个 d i di di较为方便.
a i ai ai进行排序后,显然 d i = a i − a 1 di=ai-a1 di=aia1.
对于每一个 d i di di,如何才能使得它的值变的更小呢.显然和当前最小的元素和最大的元素有关,要么是 a 1 a1 a1放到 [ i + 1 , n ] 上 , 要 么 就 是 把 a i 放 到 [ i + 1 , n ] 上 [i+1,n]上,要么就是把ai放到[i+1,n]上 [i+1,n],ai[i+1,n].但是这样做会影响到区间 [ i + 1 , n ] 上 的 d i 的 取 值 [i+1,n]上的di的取值 [i+1,n]di
上述思想启发我们,应该使用区间动态规划解决上述的影响.
d p ( l , r ) 代 表 该 区 间 上 的 ∑ i = l n d i 的 最 小 值 dp(l,r)代表该区间上的\sum_{i=l}^ndi的最小值 dp(l,r)i=lndi d p ( l , r ) = a r − a l + m i n ( d p ( l + 1 , r ) , d p ( l , r − 1 ) ) dp(l,r)=a_r-a_l+min(dp(l+1,r),dp(l,r-1)) dp(l,r)=aral+min(dp(l+1,r),dp(l,r1))
dp式子是如何推出来的呢,观察长度为3的区间: a 1 , a 2 , a 3 ( a 1 < a 2 < a 3 ) a1,a2,a3(a1a1,a2,a3(a1<a2<a3),其中d3=a3-a1,是无论如何都没有办法改变的.那么只有区间 [ 1 , 2 ] [1,2] [1,2]的值可以改变.它要么是a2 - a1 要么是 a3 -a2 .前者是不动,后者则是把a1与a3交换位置即可.其实就是考虑分别把最大值踢掉,那么考虑的区间就是 [ l , r − 1 ] [l,r-1] [l,r1]反之,如果把最小值踢掉,就是 [ l + 1 , r ] [l+1,r] [l+1,r]两者取min即可

#include
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define int long long
signed main(){
//    freopen("1.txt","r",stdin);
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
    int n;cin>>n;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
    	cin>>a[i];
	}
	sort(a.begin()+1,a.end());
	vector<vector<int>> dp(n+1,vector<int>(n+1,0));
	for(int len=2;len<=n;len++){
		for(int i=1;i+len-1<=n;i++){
			int j = i+len-1;
			dp[i][j]=a[j]-a[i]+min(dp[i+1][j],dp[i][j-1]);
		}
	}
	cout<<dp[1][n]<<"\n";
}

你可能感兴趣的:(CF,c语言,动态规划,算法)