Description
【问题背景】
小K攒足了路费来到了教主所在的宫殿门前,但是当小K要进去的时候,却发现了要与教主守护者进行一个特殊的游戏,只有取到了最大值才能进去Orz教主……
【问题描述】
守护者拿出被划分为n个格子的一个圆环,每个格子上都有一个正整数,并且定义两个格子的距离为两个格子之间的格子数的最小值。环的圆心处固定了一个指针,一开始指向了圆环上的某一个格子,你可以取下指针所指的那个格子里的数以及与这个格子距离小于k的格子的数,取一个数的代价即这个数的值。指针是可以转动的,每次转动可以将指针由一个格子转向其相邻的格子,且代价为圆环上还剩下的数的最大值。
现在对于给定的圆环和k,求将所有数取完所有数的最小代价。
Input
输入文件的第1行有两个正整数n和k,描述了圆环上的格子数与取数的范围。
第2行有n个正整数,按顺时针方向描述了圆环上每个格子上的数,且指针一开始指向了第1个数字所在的格子。
所有整数之间用一个空格隔开,且不超过10000。
Output
输出文件仅包括1个整数,为取完所有数的最小代价。
Solution
这道题用区间DP,虽然看起来不是特别明显……
我们首先设
f
[
l
]
[
r
]
[
0
/
1
]
f[l][r][0/1]
f[l][r][0/1]表示把
l
l
l到
r
r
r之间的数全部取了,0表示在指针在
l
−
k
−
1
l-k-1
l−k−1处,1表示指针在
r
+
k
+
1
r+k+1
r+k+1处。
首先我们知道。指针在能取数的时候是必须取数的,否则答案有可能不是最优,我们就可以先把初始位置附近能取的都取了,然后再开始转移。
先把转移式给出来:
f
[
l
+
1
]
[
r
]
[
0
]
=
m
i
n
(
f
[
l
]
[
r
]
[
0
]
+
m
x
[
l
]
[
r
]
,
m
i
n
(
f
[
l
]
[
r
]
[
1
]
+
m
x
[
l
]
[
r
]
∗
(
n
−
2
∗
k
−
r
+
l
−
1
)
,
f
[
l
+
1
]
[
r
]
[
0
]
)
)
f[l+1][r][0]=min(f[l][r][0]+mx[l][r],min(f[l][r][1]+mx[l][r]*(n-2*k-r+l-1),f[l+1][r][0]))
f[l+1][r][0]=min(f[l][r][0]+mx[l][r],min(f[l][r][1]+mx[l][r]∗(n−2∗k−r+l−1),f[l+1][r][0]))
f
[
l
]
[
r
−
1
]
[
1
]
=
m
i
n
(
f
[
l
]
[
r
]
[
1
]
+
m
x
[
l
]
[
r
]
,
m
i
n
(
f
[
l
]
[
r
]
[
0
]
+
m
x
[
l
]
[
r
]
∗
(
n
−
2
∗
k
−
r
+
l
−
1
)
,
f
[
l
]
[
r
−
1
]
[
1
]
)
)
f[l][r-1][1]=min(f[l][r][1]+mx[l][r],min(f[l][r][0]+mx[l][r]*(n-2*k-r+l-1),f[l][r-1][1]))
f[l][r−1][1]=min(f[l][r][1]+mx[l][r],min(f[l][r][0]+mx[l][r]∗(n−2∗k−r+l−1),f[l][r−1][1]))
(
n
−
2
∗
k
−
r
+
l
−
1
)
(n-2*k-r+l-1)
(n−2∗k−r+l−1)表示的是从左边走到右边(或从右边走到左边)需要走的步数。
m
x
[
]
[
]
mx[][]
mx[][]是要预处理出来的。
多看几遍,多理解几遍,就能懂了(有什么不懂得可以在下方评论)。
Code
#include<bits/stdc++.h>
#define rg register int
using namespace std;
int n,k,a[2005],mx[2005][2005],f[2005][2005][2],ans=99999999,ans1;
int main()
{
scanf("%d%d",&n,&k);
for(rg i=1;i<=n;i++) scanf("%d",&a[i]),ans1+=a[i];
for(rg i=1;i<=n;i++)
for(rg j=i;j<=n;j++)
mx[i][j]=max(mx[i][j-1],a[j]);
for(rg i=1;i<=n;i++)
for(rg j=1;j<=n;j++)
f[i][j][0]=f[i][j][1]=99999999;
f[k+2][n-k][0]=f[k+2][n-k][1]=0;
for(rg r=n-k;r>=k+2;r--)
for(rg l=k+2;l<=r;l++)
{
f[l+1][r][0]=min(f[l][r][0]+mx[l][r],min(f[l][r][1]+mx[l][r]*(n-2*k-r+l-1),f[l+1][r][0]));
f[l][r-1][1]=min(f[l][r][1]+mx[l][r],min(f[l][r][0]+mx[l][r]*(n-2*k-r+l-1),f[l][r-1][1]));
}
for(rg i=k+2;i<=n-k+1;i++)
ans=min(ans,min(f[i][i-1][1],f[i][i-1][0]));
printf("%d",ans+ans1);
return 0;
}