【Luogu】 P5774 [JSOI2016]病毒感染

题目链接

点击打开链接

题目解法

  • 这道题题目描述中有个问题,应该是

J Y Y JYY JYY 从村庄 j j j 前往村庄 k k k,并满足 ∣ k − i ∣ < ∣ i − j ∣ ∣k−i∣<∣i−j∣ ki∣<∣ij

根据上面的条件可以推断出 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 是一开始就被治愈还是返回来在被治愈

  1. 一开始就被治愈
    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 天的人
  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]+(rl)3a[l]
    l + 1 l+1 l+1 r r r 的村庄会多死 1 1 1 天的人,而 l l l 村庄会多死 3 ( r − l ) 3(r-l) 3(rl) 天的人,因为回到 l l l 时, l + 1 l+1 l+1 r r r 的村庄都已经花了一天时间被治愈

计算答案考虑 f [ i ] f[i] f[i] 表示 1 − i 1-i 1i 每个村庄都被治愈,现在 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[j1]+dp[j][i]+(4(ij)+2)(sum[n]sum[i])}

#include 
#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;
}

你可能感兴趣的:(Luogu,算法)