P5774 病毒感染

题面

P5774 病毒感染

\(n\)个小镇,每个小镇\(a_i\)个人感染了病毒,\(JYY\)每到一个村庄可以选择救治该村所有的人(这一天没有人死亡),或者去下一个村庄,当他已经跳过一个村庄后再向该村庄走时(此处不明白请仔细看题目中绝对值的关系那个地方),必须来救治该村庄

\(i\)个村假设有\(a_i\)个人感染,那么第二天这\(a_i\)个人会死亡且会新感染\(a_i\)个人,求最小死亡数

\(1\le n\le3000,1\le a_i\le10^9\)

思路

这题真的是普及+/提高吗?

  • \(50pts\)

定义\(f[i]\)为治愈前\(i\)个村庄的最小死亡数

对于每个村庄来说\(JYY\)可以选择治疗还是不治疗,重点在于怎么处理回去这的问题

由题目中\(|k-i|<|k-j|\)可得只要想从\(j\)回去治疗\(k\),那就必须把之前的全都治了

所以我们只需要枚举\(k\)即可实现转移

复杂度\(O(n^3)\),期望得分:\(50\)

  • \(100pts\)

上面的做法时间主要浪费在计算略过村庄再回来的死亡人数上,我们可以考虑预处理这一部分

定义\(g[i][j]\)表示从\(i\)\(j\)在回到\(i\)的最少死亡人数

但是我不知道\(g[i][j]\)应该怎么转移(看不懂题解),先挖个坑,以后回来写完

回来填坑了

枚举\(i\)为起点,\(j\)为长度,\(sum[i]=\sum\limits_{k=1}^{i}a[k]\)\(g[j][i+j]=g[j+1][i+j]+\min((sum[i+j]-sum[j])*2,a[j]*i*3+sum[i+j]-sum[j])\)

则设\(f[i]\)为前\(i\)个村庄消灭疫情最小死亡人数

\(f[i]=\min(f[j]+g[j+1][i]+(4*i-4*j-2)*(sum[n]-sum[i]))\)

淦,这转移真恶心,如果看不懂请点这里

code

/*
@ author:pyyyyyy/guhl37
-----思路------

-----debug-------
忘记初始化了,qwq 
*/
#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=3020;
int n,a[N],f[N],sum[N],g[N][N];
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
	for(int i=1;i<=n-1;++i)
		for(int j=1;j<=n;++j)
			if(i+j<=n)
				g[j][i+j]=g[j+1][i+j]+min((sum[i+j]-sum[j])*2,a[j]*i*3+sum[i+j]-sum[j]);
	memset(f,0x3f3f3f,sizeof(f));f[0]=0;
	for(int i=1;i<=n;++i)
		for(int j=0;j<i;++j)
			f[i]=min(f[j]+g[j+1][i]+(4*i-4*j-2)*(sum[n]-sum[i]),f[i]);
	cout<<f[n];
	return 0;
}


posted @ 2020-06-17 11:23  pyyyyyy  阅读(202)  评论(0编辑  收藏  举报