题目链接 :https://www.luogu.com.cn/problem/P1115
如题,先分析复杂度。 n的范围是 2* 10^5,对应之前总结的复杂度问题,nlogn可以解决 10^5,这个题能解决一半
从而这个题只能考虑n线性计算的复杂度,这里贪心算法 和 一维dp可以解决,两个方法思想上是一致的
先来分治,这个代码过不了会TLE,仅学习(这个代码是寒假集训时针对分治算法讲的)
#include<bits/stdc++.h> using namespace std; int a[200005]; int cnt; //递归次数 int maxhe; //最大和 int n; int pos(int mid) { int i; int maxl=0,ansl=a[mid]; for(i=mid;i>=1;i--) { maxl+=a[i]; ansl=max(maxl,ansl); } int maxy=0,ansy=a[mid+1]; for(i=mid+1;i<=n;i++) { maxy+=a[i]; ansy=max(maxy,ansy); } return ansl+ansy; } int fen(int left,int right) { int l,r; int mid; mid = (left+right)/2; if(left==right) return a[mid]; else { int maxl=fen(left,mid); int maxy=fen(mid+1,right); int maxz=pos(mid); //横跨两边 return max(max(maxl,maxy),maxz); } } int main() { int i; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; cout<<fen(1,n)<<endl; }
然后是贪心,这个比较好理解,就是我们用一个变量一直累加,一边累加一边判断去最大值,如果累加数变为了负数,那么我们就清零,之前的数不要了,重新从下一个数开始取
#include<bits/stdc++.h> using namespace std; #define ll long long const ll maxt = 2*1e5+5; ll a[maxt]; ll s[maxt]; ll n; int main() { cin>>n; ll sum=0;ll ma=-99999999999; cin>>sum; ma=sum; for(ll i=2;i<=n;i++) { cin>>a[i]; sum+=a[i]; ma = max(ma,sum); if(sum<0)//贪心在后面,确保0不会被当做有效值 sum=0; } cout<<ma; }
最后是dp,这是一个线性的一维dp。
如果之前去过连续的几个数字大于0,那么我当前dp数组就在这个基础上加上我本身的数,否则就从我本身这个数重新计算
但是我本身这个数也不一定是个大数,,其实就是从贪心的角度上演变过来的
#include<bits/stdc++.h> using namespace std; int n,a[200020],b[200020],i,ans=-2147483647; int main(){ cin>>n; for(i=1;i<=n;i++){ cin>>a[i]; if(i<2) b[i]=a[i]; else b[i]=max(a[i],b[i-1]+a[i]); ans=max(ans,b[i]); } cout<<ans; return 0; }