xdoj  1241---余神的rp机

核💗:

  1:  问题的转化 :   在数组找m段连续子序列 【连续子序列的值==子序列最小值*子序列的长度】使m段值之和最大

  2: 状态描述:       dp[i][j] 【前i个元素j段 且最后一段以j结尾的最大值】

  3: 状态转移         dp[i][j]=max ( _max[k-1][j-1]+ _min (k,i)*(i-k+1) )    j<=k<=i

                                   【_min (k,i) 表示最后一段从k开始到i结束的最小值】

          【_max[k-1][j-1]表示: max (dp[t][j-1] )  t<=k-1; 前t段的最大值】

     4:时间复杂度O(n^2m)...感觉肯定有更好的方法!!!  欢迎讨论+告知。 q:821474143  

     5: 空间复杂度可以继续优化: 比如可以不需要开辟dp[][],_max[][]可以简化至一维

 

 

 

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=507;
 4 int dp[N][55];
 5 int s[N];
 6 int _max[N][55];
 7 int n,m;
 8 int main ()
 9 {
10     int T; scanf ("%d",&T);
11     while (T--) {
12         memset (dp,0,sizeof(dp));
13         memset (_max,0,sizeof(_max));
14         scanf ("%d %d",&n,&m);
15         for (int i=1;i<=n;i++) scanf ("%d",&s[i]);
16         for (int j=1;j<=m;j++) {
17             dp[j][j]=dp[j-1][j-1]+s[j];
18             for (int i=j+1;i<=n;i++) {
19                 int tmp=0; int _min=0x3f3f3f3f;
20                 for (int k=i;k>=j;k--) {
21                     _min=min (_min,s[k]);
22                     int x=_min*(i-k+1);
23                     tmp=max (x,tmp);
24                     dp[i][j]=max (dp[i][j],_max[k-1][j-1]+tmp);
25                 }
26                 _max[i][j]=max (_max[i-1][j],dp[i][j]);
27             }
28         }
29         int ans=0;
30         for (int i=m;i<=n;i++)
31             ans=max (ans,dp[i][m]);
32         printf("%d\n", ans);
33     }
34     return 0;
35 }