没有题解,来水一发
可以发现往左走就要把左边所有没治愈的村庄治愈
过程可以分为几段,每段以任意顺序治愈后回到该段起点,再治愈其它段
设$f_i$表示治愈前$i$个村庄最小死亡人数,$s_i=\sum\limits_{j=1}^i a_i$,$w_{i,j}$为从$i$出发治愈$[i,j]$所有村庄再返回$i$的最小死亡人数,转移方程为
$$
f_i=\min\limits_{j<i}\{f_j+[j\not=0](s_n-s_j)+w_{j+1,i}+[i\not=n](i-j-1)(s_n-s_i)\}
$$
$f_0=0$
$w_{i,j}$从$w_{i+1,j}$转移,枚举$i$开始治不治
$$
w_{i,j}=w_{i+1,j}+\min
\begin{cases}
2(s_n-s_i)+(s_n-s_j)\\
3(j-i)a_i+(s_n-s_i)+2(s_n-s_j)\\
\end{cases}
$$
$w_{i,i}=s_n-s_i$
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N = 3005;
int n;ll a[N],s[N]; ll w[N][N],f[N];
inline ll min(ll a,ll b){return a < b ? a : b;}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&a[i]),s[i] = s[i-1] + a[i];
for (int j = 1;j <= n;++j) {
w[j][j] = s[n]-s[j];
for (int i = j-1;i;--i)
w[i][j] = w[i+1][j] + min(2*(s[n]-s[i]) + s[n]-s[j],3*a[i]*(j-i) + 2*(s[n]-s[j]) + s[n]-s[i]);
}
memset(f,0x3f,sizeof(f)),f[0]=0;
for(int i = 1;i <= n;++i)
for(int j = 0;j < i;++j)
f[i] = min(f[i],f[j] + (j != 0)*(s[n]-s[j]) + w[j+1][i] + (i-j-1)*(s[n]-s[i]));
printf("%lld\n",f[n]);
return 0;
}
大家自己扔进自己的Markdown吧qwq
可以发现往左走就要把左边所有没治愈的村庄治愈
过程可以分为几段,每段以任意顺序治愈后回到该段起点,再治愈其它段
设$f_i$表示治愈前$i$个村庄最小死亡人数,$s_i=\sum\limits_{j=1}^i a_i$,$w_{i,j}$为从$i$出发治愈$[i,j]$所有村庄再返回$i$的最小死亡人数,转移方程为
$$
f_i=\min\limits_{j<i}\{f_j+[j\not=0](s_n-s_j)+w_{j+1,i}+[i\not=n](i-j-1)(s_n-s_i)\}
$$
$f_0=0$
$w_{i,j}$从$w_{i+1,j}$转移,枚举$i$开始治不治
$$
w_{i,j}=w_{i+1,j}+\min
\begin{cases}
2(s_n-s_i)+(s_n-s_j)\\
3(j-i)a_i+(s_n-s_i)+2(s_n-s_j)\\
\end{cases}
$$
$w_{i,i}=s_n-s_i$
为什么往左走就一定能满足那个条件,要是k在左边紧挨着j,然后i距离j很远,那样k-i距离比k-j更大
为什么latex挂了