感受
还
是
挺
容
易
想
到
的
区
间
D
P
,
但
是
如
果
对
区
间
D
P
理
解
不
透
彻
可
能
会
T
L
E
还是挺容易想到的区间DP,但是如果对区间DP理解不透彻\\可能会TLE
还是挺容易想到的区间DP,但是如果对区间DP理解不透彻可能会TLE
思路
考
虑
连
续
区
间
合
并
,
而
且
费
用
最
少
,
推
断
是
区
间
D
P
。
考虑连续区间合并,而且费用最少,推断是区间DP。
考虑连续区间合并,而且费用最少,推断是区间DP。
考
虑
有
L
与
R
限
制
,
推
断
D
P
状
态
是
3
维
的
。
设
d
p
[
l
]
[
r
]
[
k
]
表
示
区
间
[
l
,
r
]
合
并
后
剩
余
k
堆
的
最
小
值
考虑有L与R限制,推断DP状态是3维的。\\设dp[l][r][k]表示区间[l,r]合并后剩余k堆的最小值
考虑有L与R限制,推断DP状态是3维的。设dp[l][r][k]表示区间[l,r]合并后剩余k堆的最小值
考
虑
d
p
[
l
]
[
r
]
[
k
]
如
何
转
移
?
考虑dp[l][r][k]如何转移?
考虑dp[l][r][k]如何转移?
[
l
,
r
]
区
间
转
移
肯
定
是
区
间
[
l
,
m
i
d
]
+
[
m
i
d
+
1
,
r
]
区
间
转
移
[l,r]区间转移肯定是区间[l,mid]+[mid+1,r]区间转移
[l,r]区间转移肯定是区间[l,mid]+[mid+1,r]区间转移
那
么
k
如
何
转
移
呢
?
那么k如何转移呢?
那么k如何转移呢?
如
果
[
l
,
m
i
d
]
与
[
m
i
d
+
1
,
r
]
只
是
单
纯
拼
接
,
那
么
k
由
[
l
,
m
i
d
]
提
供
k
−
1
,
[
m
i
d
+
1
,
r
]
提
供
1
如果[l,mid]与[mid+1,r]只是单纯拼接,那么\\k由[l,mid]提供k-1,[mid+1,r]提供1
如果[l,mid]与[mid+1,r]只是单纯拼接,那么k由[l,mid]提供k−1,[mid+1,r]提供1
如
果
合
并
则
,
k
=
1
,
合
并
处
理
即
可
如果合并则,k=1,合并处理即可
如果合并则,k=1,合并处理即可
因
此
d
p
转
移
式
子
得
出
:
因此dp转移式子得出:
因此dp转移式子得出:
拼
接
:
d
p
[
l
]
[
r
]
[
k
+
1
]
=
m
i
n
(
d
p
[
l
]
[
r
]
[
k
+
1
]
,
d
p
[
l
]
[
m
i
d
]
[
k
]
+
d
p
[
m
i
d
+
1
]
[
r
]
[
1
]
)
拼接:dp[l][r][k+1]=min(dp[l][r][k+1], dp[l][mid][k]+dp[mid+1][r][1])
拼接:dp[l][r][k+1]=min(dp[l][r][k+1],dp[l][mid][k]+dp[mid+1][r][1])
合
并
:
d
p
[
l
]
[
r
]
[
1
]
=
m
i
n
(
d
p
[
l
]
[
r
]
[
1
]
,
d
p
[
l
]
[
m
i
d
]
[
k
]
+
d
p
[
m
i
d
+
1
]
[
r
]
[
1
]
+
s
u
m
[
r
]
−
s
u
m
[
l
−
1
]
)
其
中
s
u
m
[
i
]
表
示
前
缀
和
合并:dp[l][r][1]=min(dp[l][r][1],dp[l][mid][k]+dp[mid+1][r][1]+sum[r]-sum[l-1])其中sum[i]表示前缀和
合并:dp[l][r][1]=min(dp[l][r][1],dp[l][mid][k]+dp[mid+1][r][1]+sum[r]−sum[l−1])其中sum[i]表示前缀和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 1e18;
const int maxn = 200;
int n, L, R;
ll sum[maxn];
ll dp[maxn][maxn][maxn];
void init(){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
for(int k = 1; k <= n; k++){
dp[i][j][k] = inf;
}
}
dp[i][i][1] = 0;
}
}
void print(int len){
for(int l = 1, r; ; l++){
r = l + len - 1; if(r > n) break;
for(int k = 1; k <= len; k++){
printf("dp[%d][%d][%d] = %lld\n", l, r, k, dp[l][r][k]);
}
}
}
int main(){
while(scanf("%d%d%d", &n, &L, &R) != EOF){
init();
ll v;
for(int i = 1; i <= n; i++){
scanf("%lld", &v); sum[i] = sum[i - 1] + v;
}
for(int len = 2; len <= n; len++){
for(int l = 1, r; ; l++){
r = l + len - 1; if(r > n) break;
for(int mid = 1; mid < r; mid++){
for(int k = 1; k < len; k++){
dp[l][r][k + 1] = min(dp[l][r][k + 1], dp[l][mid][k] + dp[mid + 1][r][1]);
if(k + 1 >= L && k + 1 <= R) dp[l][r][1] = min(dp[l][r][1], dp[l][mid][k] + dp[mid + 1][r][1] + sum[r] - sum[l - 1]);
}///dp[l][mid][k] + dp[mid+1][r][1]合并
}
}
//print(len);
}
if(dp[1][n][1] >= inf) puts("0");
else printf("%lld\n", dp[1][n][1]);
}
return 0;
}