Treats for the Cows G/S——区间dp
P2858 [USACO06FEB]Treats for the Cows G/S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
不得不说,这道题有一点颠覆我的思维方式。
刚开始,我觉得这道题和合唱队那道题一样(其实就是差不多),但是我就是固定思维想用个三维数组,分别求出在左边和在右边的最大值,最后进行比较得出答案。笨蛋!人家又不是只能一直从一边出来,正确的思考应该是从左出来点,从右出来点。
状态表示:区间[i,j]的最大价值。
状态计算:可以从左端点出来,f[i+1,j]+v[i]*(n-len+1) //n-len+1怎么来的? 后面有
可以从右端点出来,f[i,j-1]+v[j]*(n-len+1)
f[i,j]就是上述两种表达式求max
最终求得是f[1][n]
初始化:因为方程表示的是区间[i,j]的最大价值,所以f[i,i]应该初始化为v[i]*n,n是最大的天数,这样才满足最大价值。
因此状态计算中的(n-len+1)就是对应的天数。emmmm,这也就是颠覆我的地方。这个天数表示的意思就是它是倒着卖的,最后一天卖的是f[i,i],第一天卖的是f[1,n],而这样倒着卖的原因就是初始化的时候根据方程定义,把f[i,i]初始化为最大天数才卖掉它,这样才符合方程定义。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=2e3+100; 4 typedef long long ll; 5 ll f[N][N],v[N]; 6 7 8 int main() 9 { 10 int n;scanf("%d",&n); 11 for(int i=1;i<=n;i++)scanf("%d",&v[i]); 12 13 for(int len=1;len<=n;len++) 14 { 15 for(int i=1;i+len-1<=n;i++) 16 { 17 int j=i+len-1; 18 if(i==j) 19 { 20 f[i][j]=v[i]*n; 21 continue; 22 } 23 f[i][j]=max(f[i][j-1]+v[j]*(n-len+1),f[i+1][j]+v[i]*(n-len+1)); 24 } 25 } 26 printf("%lld\n",f[1][n]); 27 28 29 return 0; 30 }