题目链接
题目解法
- 这道题题目描述中有个问题,应该是
J Y Y JYY JYY 从村庄 j j j 前往村庄 k k k,并满足 ∣ k − i ∣ < ∣ i − j ∣ ∣k−i∣<∣i−j∣ ∣k−i∣<∣i−j∣
根据上面的条件可以推断出
J
Y
Y
JYY
JYY 行走的路一定是一段连着一段的,即从一段的开头往末尾走,然后再回到开头,把原先没有治愈的村庄治愈,再到下一段的开头继续往后走
由此可以预处理出
d
p
[
l
]
[
r
]
dp[l][r]
dp[l][r] 表示走
l
l
l 到
r
r
r 的一段的最小代价,行走的路线是
l
−
>
r
−
>
l
l->r->l
l−>r−>l
考虑转移,可以发现
d
p
[
l
+
1
]
[
r
]
dp[l+1][r]
dp[l+1][r] 的路线是
l
+
1
−
>
r
−
>
l
+
1
l+1->r->l+1
l+1−>r−>l+1,比较好转移到
d
p
[
l
]
[
r
]
dp[l][r]
dp[l][r],所以有
d
p
[
l
+
1
]
[
r
]
dp[l+1][r]
dp[l+1][r] 转移到
d
p
[
l
]
[
r
]
dp[l][r]
dp[l][r],只需要考虑
l
l
l 是一开始就被治愈还是返回来在被治愈
- 一开始就被治愈
d p [ l ] [ r ] = d p [ l + 1 ] [ r ] + 2 ∗ ( s u m [ r ] − s u m [ l ] ) dp[l][r]=dp[l+1][r]+2*(sum[r]-sum[l]) dp[l][r]=dp[l+1][r]+2∗(sum[r]−sum[l])
即 l + 1 l+1 l+1 到 r r r 的村庄会多死 2 2 2 天的人 - 返回时再被治愈
d p [ l ] [ r ] = d p [ l + 1 ] [ r ] + s u m [ r ] − s u m [ l ] + ( r − l ) ∗ 3 ∗ a [ l ] dp[l][r]=dp[l+1][r]+sum[r]-sum[l]+(r-l)*3*a[l] dp[l][r]=dp[l+1][r]+sum[r]−sum[l]+(r−l)∗3∗a[l]
即 l + 1 l+1 l+1 到 r r r 的村庄会多死 1 1 1 天的人,而 l l l 村庄会多死 3 ( r − l ) 3(r-l) 3(r−l) 天的人,因为回到 l l l 时, l + 1 l+1 l+1 到 r r r 的村庄都已经花了一天时间被治愈
计算答案考虑
f
[
i
]
f[i]
f[i] 表示
1
−
i
1-i
1−i 每个村庄都被治愈,现在
J
Y
Y
JYY
JYY 再第
i
+
1
i+1
i+1 个村庄的最小代价
可以考虑代价提前计算,把
i
+
1
i+1
i+1 到
n
n
n 村庄在当前时间段死的人都提前记录进
f
f
f
转移式即为
f
[
i
]
=
m
i
n
{
f
[
j
−
1
]
+
d
p
[
j
]
[
i
]
+
(
4
∗
(
i
−
j
)
+
2
)
∗
(
s
u
m
[
n
]
−
s
u
m
[
i
]
)
}
f[i]=min\{f[j-1]+dp[j][i]+(4*(i-j)+2)*(sum[n]-sum[i])\}
f[i]=min{f[j−1]+dp[j][i]+(4∗(i−j)+2)∗(sum[n]−sum[i])}
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N(3100);
int n,a[N],sum[N],dp[N][N],f[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
signed main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
for(int len=2;len<=n;len++)
for(int l=1,r=len;r<=n;l++,r++)
dp[l][r]=min(dp[l+1][r]+2*(sum[r]-sum[l])/*开始就治愈i村庄*/,
dp[l+1][r]+sum[r]-sum[l]+(r-l)*3*a[l]/*回来时在治愈i村庄*/);
memset(f,0x3f,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i]=min(f[i],f[j-1]+dp[j][i]+(4*(i-j)+2)*(sum[n]-sum[i]));
printf("%lld",f[n]);
return 0;
}