UVa:11078 Open Credit System


这里我是用分治法做的。方法有点像算法导论上求最大连续数组和。


求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;
}


 

你可能感兴趣的:(分治法)