其他分享
首页 > 其他分享> > P5774 [JSOI2016]病毒感染

P5774 [JSOI2016]病毒感染

作者:互联网

间隙

大致题意

有\(n\)个疫情城市,每个城市\(i\)在未被治愈时每天会死\(a_i\)个人,现在从一号城市出发,每一天可以选择:

花费一天时间彻底治愈目前所在的城市的所有患者。这一天不会有任何患者死去;

花费一天的时间前往一个相邻的村庄,若往左走则需要沿路把左边所有未治愈的城市治愈。

求最少死亡人数。

分析

设\(f_i\)表示前\(i\)个城市的最少死亡人数

\(w(i,j)\)表示从\(i\)走到\(j\)再走回\(i\)时的最少死亡人数

\(sum_i\)表示城市每日死亡人数的前缀和

可以看出是个经(tao)典(lu)\(dp\),有显然的转移方程

\(f_i = min(f_j+w(j+1,i)+(4×(i-j)-2)×(sum_n-sum_i))\)

问题在于如何来搞出\(w(i,j)\)

\(w(i,j)\)具有最有子结构性质,考虑使用区间\(dp\)的方法来预处理

显然,一个城市至多只会被经过两次,因此一个城市被治愈的时间只有两种可能:

1.在第一次被经过时被治愈

2.在第二次被经过时治愈

若第一次经过时花费一天的时间去治愈,后面的城市都会多死亡\(sum_j - sum_i\)个人,反之该城市需要经过\(3×j\)天后才能被治愈,也就是会多死亡\(3×(j-i)×a_i\)个人

得到转移方程:

\(w(i,j) = w(i+1,j)+min(2×(sum_j-sum_i),a_i×3×(j-i)+sum_j-sum_i)\)

\(code\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3010;
long long n,a[MAXN];
long long f[MAXN][MAXN],sum[MAXN]; 
long long ans[MAXN];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		sum[i] = sum[i-1]+a[i];
	}
	memset(ans,0x3f,sizeof(ans));
    memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++){
		f[i][i] = 0;
	}
	for(int len=1;len<=n-1;len++){
		for(int i=1;i+len<=n;i++){
			int j=i+len;
			f[i][j] = f[i+1][j]+min(2*(sum[j]-sum[i]),a[i]*3*len+sum[j]-sum[i]);
		}
	}
	ans[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<i;j++){
			ans[i] = min(ans[j]+f[j+1][i]+(4*(i-j)-2)*(sum[n]-sum[i]),ans[i]);
		}
	}
	cout<<ans[n]<<endl;
}

标签:JSOI2016,sum,P5774,long,病毒感染,死亡,MAXN,治愈,城市
来源: https://www.cnblogs.com/xcxc82/p/13911933.html