P2904 [USACO08MAR]River Crossing S
考察:线性dp
思路:
很容易想到f[i][j]表示前i趟运了j头牛的最小时间(本蒟蒻虽然想到了但因为会T放弃了这个想法,所以会T的做法先想想看能不能优化啊啊啊)
所以f[i][j] = f[i-1][k]+sum[j-k]+2*m(这里会在最后一次多算一次m,最后答案减去即可).最后答案是f[i][n]
很明显三重循环直接T了,考虑优化,很容易想到分级那道题的优化方式,但是这道题用不了分级的优化.可以发现每个f[i][j]都要与<=j的f[i][k]比较 ,且后面的sum数组也是变量.也就是说j在k1处取最小值,但这j+1在k1处就不一定取最小值.
这题不知道为什么能把i循环去掉,感觉很迷.
根据其他题解说仔细观察,本蒟蒻唯一发现的是转移方程先更新f[k]再更新f[j]更新在f[k]的2*m会叠加在f[j]上,然后可以发现转移方程与i无关.
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <unordered_map> 5 using namespace std; 6 const int N = 2510; 7 int sum[N],n,m,f[N]; 8 int solve() 9 { 10 memset(f,0x3f,sizeof f); 11 f[0] = 0; 12 for(int j=1;j<=n;j++) 13 { 14 for(int k=0;k<=j;k++) 15 f[j] = min(f[k]+sum[j-k]+2*m,f[j]); 16 } 17 return f[n]-m; 18 } 19 int main() 20 { 21 scanf("%d%d",&n,&m); 22 for(int i=1;i<=n;i++) scanf("%d",&sum[i]),sum[i]+=sum[i-1]; 23 printf("%d\n",solve()); 24 return 0; 25 }