hdu 5289 Assignment(2015多校第一場第2題)RMQ+二分(或者multiset模擬過程)

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5289

題意:給你n個數和k,求有多少的區間使得區間內部任意兩個數的差值小於k,輸出符合要求的區間個數

思路:求出區間的最大最小值,只要他們的差值小於k,那麼這個區間就符合要求,但是由於n較大,用暴力一定超時,所以就要用別的方法了;而RMQ是可以求區間的最值的,而且預處理的複雜度只有O(nlogn),而查詢只是O(1)處理,這樣相對來說節約了時間,再根據右端點來二分枚舉左端點(其實不用二分好像更快,估計是數據問題)。

而另一種方法不得不說,學了C++的一定要在認真的去看一下STL的那些用法,這次用multiset來做就大大的節約時間,而且又不用思考太多,只要從左到右模擬區間,就可以了。


(RMQ+二分)代碼:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
#define LL __int64
#define INF 0x3f3f3f3f
const int MAXN=100005;
#define mod 1000000007

int a[MAXN];
LL ans;
int dp1[MAXN][30],dp2[MAXN][30];

void init(int n)
{
    for(int i=1;i<=n;i++)
        dp1[i][0]=dp2[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++)
    {
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]);
            dp2[i][j]=min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]);
        }
    }
}

int RMQ(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1)k++;
    return max(dp1[L][k],dp1[R-(1<<k)+1][k])-min(dp2[L][k],dp2[R-(1<<k)+1][k]);
}

int binarySearch(int L,int R,int n,int k)
{
    int mid;
    int l=L,r=R;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(RMQ(mid,R)>=k)
        {
            l=mid+1;
        }
        else
        {
            r=mid-1;
        }
    }
    if(RMQ(mid,R)>=k)
        mid++;
    return mid;
}
int main()
{
    int T,i,j,n,k,mi,ma,l,r;
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            scanf("%d%d",&n,&k);
            for(i=1;i<=n;i++)
                scanf("%d",&a[i]);
            if(!k)
            {
                printf("0\n");
                continue;
            }
            if(k==1)
            {
                printf("%d\n",n);
                continue;
            }
            init(n);
            ans=0;
            for(i=j=1;i<=n;i++)
            {
                j=binarySearch(j,i,n,k);
                ans+=i-j+1;
            }
            printf("%I64d\n",ans);
        }
    }
    return 0;
}


(STL)代碼:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
#define LL __int64
#define INF 0x3f3f3f3f
const int MAXN=100005;
#define mod 1000000007

int a[100005];
LL ans;
int main()
{
    int T,i,j,n,k,mi,ma,l,r;
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            scanf("%d%d",&n,&k);
            for(i=0;i<n;i++)
                scanf("%d",&a[i]);
            if(!k)
            {
                printf("0\n");
                continue;
            }
            if(k==1)
            {
                printf("%d\n",n);
                continue;
            }
            l=0;
            r=1;
            multiset<int>s;
            s.insert(a[0]);
            ans=n;
            while(1)
            {
                if(s.size())
                {
                    mi=*s.begin();
                    ma=*s.rbegin();
                    if(abs(a[r]-mi)<k&&abs(a[r]-ma)<k)
                    {
                        ans+=s.size();
                        s.insert(a[r]);
                        r++;
                        if(r==n)
                            break;
                    }
                    else
                    {
                        if(s.size())
                            s.erase(s.find(a[l]));
                        l++;
                    }
                }
                else
                {
                    l=r;
                    s.insert(a[r]);
                    r++;
                    if(r==n)
                        break;
                }
            }
            printf("%I64d\n",ans);
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章