官方题解:
这个题有非常多O(n2) 的算法。这里说一种:枚举每个区间,在枚举区间的同一时候维护区间内的最小值和区间和,将最小值与P 的大小进行比較,贪心地取最大值就可以。注意若枚举到的区间是整个数组,则P 的值是必须取的。
当然也存在O(n) 的做法:从左往右处理出dp1[i]=max(a[i],dp1[i−1]+a[i]) ,相同从右往左处理出dp2[i]=max(a[i],dp2[i+1]+a[i]) 。再枚举要改动哪一个数,用两个数组更新答案就可以。
我是用了两次dp。事实上能够合成一个的,o(n2)的也是,每改一次dp一次,写的略丑。
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<cstring> #include<algorithm> #define INF 0x3f3f3f3f3f3F #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long llu; const int maxd=1000+10; //--------------------- ll a[maxd]; ll dp[2][maxd]; ll n,p; ll DP() { dp[0][0]=max(a[0],(ll)0); for(int i=1;i<n;++i) dp[0][i]=max((ll)0,(ll)dp[0][i-1]+a[i]); ll ans=a[0]; for(int i=1;i<n;++i){ dp[1][i]=dp[0][i-1]+a[i]; ans=max(ans,dp[1][i]); } return ans; } int main() { freopen("1.txt","r",stdin); int kase; scanf("%d",&kase); while(kase--) { scanf("%I64d%I64d",&n,&p); for(int i=0;i<n;++i) scanf("%I64d",&a[i]); ll ans=-1000000000001; for(int i=0;i<n;++i) { int tmp=a[i]; a[i]=p; ans=max(ans,DP()); a[i]=tmp; } printf("%I64d ",ans); } return 0; }