核💗:
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 }
抓住青春的尾巴。。。