[区间dp][前缀和] Jzoj P4517 病毒感染

Description

 

Input

Output

 

Sample Input

6
40 200 1 300 2 10

Sample Output

1950
 

Data Constraint

 

Hint

 

题解

  • 题目大意:有n个村庄,每天每个村庄会死ai个人。JYY每天可以选择把一个村庄的人治好或者是走一步,每当他往回走就要把前面所有没有治的村庄全部治好,问JYY要把所有人治好的死亡的最少人数
  • 那么可以设f[i],为前i-1个村庄的人都治好了,现在在第i个村庄的死亡的最少人数,那么这个死亡的最少人数包括i-1个村庄的人也包括i~n村庄的人
  • 转移的话,枚举一个最左没有被治好的村庄l,f[r]=min(f[l-1]+g[l][r]),其中g[i][j]为治好村庄l到r的死亡的最少人数
  • 那么对于一条i到j的路径可以怎么走呢?
  • 对于每一个村庄可以选择第一次经过的时候治好,也可以选择掉头经过的时候治好。那么这样的话,对于r后面的村庄,他们的贡献很好计算,是一个定值,那么考虑如何计算l~r这段的贡献
  • 线段内的村庄就是就是只有两种情况,那么就可以通过g[l+1][r]转移过来,区间dp从小区间逐渐转移到大区间,就可以把所有情况都考虑完
  • 那么这样的话,我们就可以计算出g数组的值了,那么就可以通过g数组来计算最后f数组的值

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define N 3000
 5 using namespace std;
 6 int n;
 7 long long g[N][N],a[N],f[N],sum[N];
 8 int main()
 9 {
10     scanf("%d",&n),memset(f,125,sizeof(f));
11     for (int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
12     for (int i=1;i<=n;i++) g[i][i]=sum[n]-sum[i];
13     for (int i=2,k;i<=n;i++)
14         for (int j=1;j<=n-i+1;j++) k=i+j-1,g[j][k]=min(g[j+1][k]+2*(sum[n]-sum[j])+sum[n]-sum[k],g[j+1][k]+sum[n]-sum[j-1]+(3*i-4)*a[j]+2*(sum[n]-sum[k]));
15     f[0]=0,f[1]=sum[n]-sum[1];
16     for (int i=2;i<=n;i++)
17     {
18         f[i]=g[1][i]+(i-1)*(sum[n]-sum[i]);
19         for (int j=1;j<i;j++) f[i]=min(f[i],f[j]+sum[n]-sum[j]+g[j+1][i]+(i-j-1)*(sum[n]-sum[i]));
20     }
21     printf("%lld",f[n]);
22 }

 

posted @ 2019-01-18 16:24  BEYang_Z  阅读(388)  评论(0)    收藏  举报