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]初始化为最大天数才卖掉它,这样才符合方程定义。

 

 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 }
View Code

 

posted @ 2022-04-04 21:38  wellerency  阅读(33)  评论(0编辑  收藏  举报