Educational Codeforces Round 63 (Rated for Div. 2) D. Beautiful Array(动态规划.递推)
题意:
给你一个包含 n 个元素的序列 a[];
定义序列 a[] 的 beauty 为序列 a[] 的连续区间的加和最大值,如果全为负数,则 beauty = 0;
例如:
a[] = {10, -5, 10, -4, 1} ;
beauty = 15;( 10+(-5)+10 )
a[] = {-3, -5, -1};
beauty = 0;( 不取 )
给你一个整数 x,你可以将序列 a[] 的任意子序列 a[ l , r ]*x(即 a[l]=a[l]*x,a[l+1]=a[l+1]*x,.....,a[r]=a[r]*x);
当然,也可以不执行这个操作;
求 beauty 的最大值;
思路:
一看到这道题,第一反应就贪过去了;
贪了好大一会,交了几发程序,全部 "Wrong answer on test 5";
看了一眼他人的AC代码,看到了 dp 数组,然后,想了好久好久的动态规划解法;
wa 了改,改了 wa,终于,在下午临近吃饭的时候,AC了(大佬轻点虐)
假设修改的区间为[ L,R ]
那么,对于∀i∈[1,n], i = L or L < i < R or i = R;
定义 dp[ i ][ j ],含义如下:
j = 0 : i 作为修改区间的起始位置,从 i 开始向左能形成的最大区间和;
j = 1 : i 作为修改区间的中间位置,从 i 开始向左能形成的最大区间和;
j = 2 : i 作为修改区间的终点位置,i 可以形成的最大区间和;
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define INFll 0x3f3f3f3f3f3f3f3f 6 #define ll long long 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 const int maxn=3e5+50; 9 10 int n,x; 11 ll a[maxn]; 12 /** 13 在做*x的操作下 14 dp[i][0]:i位置为修改区间的开始 15 dp[i][1]:i位置为修改区间的中间部分 16 dp[i][2]:i位置为修改区间的结尾 17 */ 18 ll dp[maxn][3]; 19 /** 20 在不做*x的操作下 21 maxL[i]:以i开始的向左能形成的最大的区间和 22 maxR[i]:以i开始的向右能形成的最大的区间和 23 */ 24 ll maxL[maxn]; 25 ll maxR[maxn]; 26 27 ll Solve() 28 { 29 maxL[0]=-INFll; 30 for(int i=1;i <= n;++i) 31 maxL[i]=max(maxL[i-1]+a[i],a[i]); 32 maxR[n+1]=-INFll; 33 for(int i=n;i >= 1;--i) 34 maxR[i]=max(maxR[i+1]+a[i],a[i]); 35 36 dp[0][0]=dp[0][1]=0; 37 for(int i=1;i <= n;++i) 38 { 39 dp[i][0]=x*a[i]+(maxL[i-1] > 0 ? maxL[i-1]:0); 40 dp[i][1]=max(dp[i-1][0],dp[i-1][1])+x*a[i]; 41 dp[i][2]=max(dp[i][0],dp[i][1])+(maxR[i+1] > 0 ? maxR[i+1]:0); 42 } 43 44 ll ans=0; 45 for(int i=1;i <= n;++i) 46 ans=max(max(ans,maxL[i]),dp[i][2]); 47 48 return ans; 49 } 50 int main() 51 { 52 while(~scanf("%d%d",&n,&x)) 53 { 54 for(int i=1;i <= n;++i) 55 scanf("%lld",a+i); 56 printf("%I64d\n",Solve()); 57 } 58 }
巨巨代码(额外增加点我的注释)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 #define ll long long 5 6 int n,x; 7 ll a[300030]; 8 ll dp[300030][3]; 9 10 int main() 11 { 12 ll ans=0; 13 cin>>n>>x; 14 for(int i=1;i<=n;++i) 15 cin>>a[i]; 16 17 mem(dp[0],0); 18 /** 19 dp[i][0]:[1,i]未使用*x所形成的最大区间和 20 dp[i][1]:[L,i-1]使用*x,并且i也使用*x所形成的最大区间和 21 dp[i][2]:[L,i-1]使用*x,但是i不使用*x所形成的最大区间和 22 */ 23 for(int i=1;i<=n;++i) 24 { 25 dp[i][0]=a[i]+(dp[i-1][0] > 0 ? dp[i-1][0]:0); 26 dp[i][1]=max(0LL,max(dp[i-1][0],dp[i-1][1]))+a[i]*x; 27 dp[i][2]=max(0LL,max(dp[i-1][1],dp[i-1][2]))+a[i]; 28 for(int j=0;j<3;++j)//三者去最值 29 ans=max(ans,dp[i][j]); 30 } 31 cout<<ans<<endl; 32 33 return 0; 34 }