51nod最大字段和(1049 1254)
1049是最大字段和的最朴素版本,1254加的地方是可以交换两个数一次。
51nod 1049
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+1000; ll a[N]; int n; ll solve() { ll sum=0; ll ans=0; for(int i=1;i<=n;i++) { if(sum>0) sum+=a[i]; else sum=a[i]; ans=max(ans,sum); } return ans; } int main() { //freopen("1.txt","r",stdin); cin>>n; ll sum=0; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); sum+=a[i]; } ll ans=solve(); cout<<ans<<endl; return 0; }
51nod 1254
交换两个数可以分为三类。
1.交换的两个数都是最优解里面的。
2.交换的两个数都不是最优解里面的。
3.交换的两个数一个是最优解里面的,一个不是最优解里面的。
只有第三种才可能会对答案有贡献。
先考虑一边k<i,对于另一边分析类似。
预处理求出每个i作为结束的最大字段为maxl[i],如果为负设为0;预处理求出每个i作为起点的最大字段和为maxr[i],如果为负设为0;
对于每个i,求出左边的除最大字段和包含的点的最大值的点与i交换。贡献为maxl[i-1]+a[k]+maxr[i+1].
代码实现用sum存储以i-1为结尾的字段和除左边处字段和包含的点的最大值的点的最大值。
除左边字段和包含的所有点的最大值可以和左边字段和最大值之间可以隔负连通块,所以有sum=max(sum+a[i-1],maxx);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+100; ll a[N],maxl[N],maxr[N]; int main() { int n; //freopen("1.txt","r",stdin); cin>>n; for(int i=1;i<=n;i++) scanf("%lld",&a[i]); ll ans=0; for(int i=1;i<=n;i++) { if(maxl[i-1]>0) maxl[i]=maxl[i-1]+a[i]; else maxl[i]=a[i]; if(maxr[n-i+2]>0) maxr[n-i+1]=maxr[n-i+2]+a[n-i+1]; else maxr[n-i+1]=a[n-i+1]; maxl[i]=max(maxl[i],0ll); maxr[n-i+1]=max(maxr[n-i+1],0ll); ans=max(ans,maxl[i]); } ll maxx=a[1],sum=0; for(int i=2;i<=n;i++) { sum=max(sum+a[i-1],maxx); ans=max(ans,sum+maxr[i+1]); maxx=max(maxx,a[i]); } maxx=a[n],sum=0; for(int i=n-1;i>=1;i--) { sum=max(sum+a[i+1],maxx); ans=max(ans,sum+maxl[i-1]); maxx=max(maxx,a[i]); } cout<<ans<<endl; return 0; }