这里我是用分治法做的。方法有点像算法导论上求最大连续数组和。
求Ai-Aj最大值。
有三种情况。
1.Ai Aj都位于左段区间
2.Ai Aj都位于右段区间
3.Ai位于左段区间,Aj位于右段区间。那么如果要使Ai-Aj最大,Ai肯定是左段区间的最大值,Aj是右段区间的最小值。
1和2都是原问题的更小规模,可以分治处理。3不是,我们可以把它视作合并的过程。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define INF 1500000 using namespace std; int A[100005]; struct Num { int a,b,s; Num(){} Num(int x,int y,int z):a(x),b(y),s(z){} }; Num merge(int low,int mid,int high) { int L,R,max,min; max=-INF; for(int i=mid;i>=low;--i) { if(A[i]>=max) { max=A[i]; L=i; } } min=INF; for(int i=mid+1;i<=high;++i) { if(A[i]<=min) { min=A[i]; R=i; } } return Num(L,R,A[L]-A[R]); } Num solve(int p,int q) { if(q==p) return Num(p,q,-INF); else { int mid=(p+q)/2; Num x,m,y; x=solve(p,mid); y=solve(mid+1,q); m=merge(p,mid,q); if(x.s>=y.s&&x.s>=m.s) return x; else if(m.s>=x.s&&m.s>=y.s) return m; else return y; } } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=0;i<n;++i) scanf("%d",&A[i]); Num ans=solve(0,n-1); printf("%d\n",ans.s); } return 0; }
先这样,明天再放上O(n)的做法。
---------------------------------------------------------------------------------------------------------
O(n)的算法。
边读边算速度会更快。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int A[100005]; int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=0; i<n; ++i) scanf("%d",&A[i]); int ans=A[0]-A[1]; int MaxAi=A[0]; for(int j=1;j<n;++j) { ans=max(ans,MaxAi-A[j]); MaxAi=max(A[j],MaxAi); } printf("%d\n",ans); } return 0; }