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=ai−a1.
对于每一个
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)=ar−al+min(dp(l+1,r),dp(l,r−1))
dp式子是如何推出来的呢,观察长度为3的区间:
a
1
,
a
2
,
a
3
(
a
1
<
a
2
<
a
3
)
a1,a2,a3(a1<a2<a3)
a1,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,r−1]反之,如果把最小值踢掉,就是
[
l
+
1
,
r
]
[l+1,r]
[l+1,r]两者取min即可
#include<bits/stdc++.h>
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";
}