2015 多校赛 1002 (hdu 5289)

来源:互联网 发布:可以看本子软件 编辑:程序博客网 时间:2024/06/05 04:06
http://acm.hdu.edu.cn/showproblem.php?pid=5288
解法1:rmq算法
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>using namespace std;const int size=100010;int a[size];int dMx[size][30];int dMi[size][30];void init_rmq(int n){    int i,j;    for(i=1;i<=n;i++)    dMx[i][0]=dMi[i][0]=a[i];     for(int j = 1; (1 << j) <= n + 1; j++) {          for(int i = 0; i + (1 << j) - 1 < n + 1; i++) {              dMx[i][j] = max(dMx[i][j - 1], dMx[i + (1 << (j - 1))][j - 1]);              dMi[i][j] = min(dMi[i][j - 1], dMi[i + (1 << (j - 1))][j - 1]);          }      }  }int get(int i,int j){    int index=int(log(double(j-i+1))/log(double(2)));    int mx=max(dMx[i][index],dMx[j-(1<<index)+1][index]);    int mn=min(dMi[i][index],dMi[j-(1<<index)+1][index]);    return mx-mn;}int main(){    int i,j,t,n,m,k,left,right,mid;    long long sum=0;    scanf("%d",&t);    while(t--)    {        sum=0;        scanf("%d%d",&n,&k);        for(i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        init_rmq(n);                for(i=1;i<=n;i++)        {            left=i;right=n;            while(left<=right)            {                mid=(left+right)>>1;                if(get(i,mid)<k)                {                    left=mid+1;                }                else right=mid-1;            }            sum+=left-i;        }        printf("%I64d\n",sum);    }}解法2:单调队列
#include<stdio.h>#include<string.h>#include<iostream>#include<queue>using namespace std;const int size = 100010;deque<int > deq1,deq2;int a[size];int main(){int i,j,k,n,m,t;long long ans;scanf("%d",&t);while(t--){ans=0;scanf("%d%d",&n,&k);for(i=0;i<n;i++){scanf("%d",&a[i]);}while(!deq1.empty())deq1.pop_back();while(!deq2.empty())deq2.pop_back();for(j=0,i=0;i<n;i++){while(!deq1.empty()&&a[i]>deq1.back()) deq1.pop_back();deq1.push_back(a[i]);while(!deq2.empty()&&a[i]<deq2.back()) deq2.pop_back();deq2.push_back(a[i]);while(deq1.front()-deq2.front()>=k){ans+=(i-j);if(deq1.front()==a[j]) deq1.pop_front();if(deq2.front()==a[j]) deq2.pop_front();j++;}}while(j<n){ans+=(i-j);j++;}printf("%I64d\n",ans);}}解法三: <pre style="font-family:Courier New;text-align:left;"><pre name="code" class="html">单调队列
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;
const int size = 100010;
int deq1[size],deq2[size];
int a[size];
int main()
{
    int i,j,k,n,m,t;
    long long sum;
    int l1,l2,r1,r2,l;
    scanf("%d",&t);
    while(t--)
    {
        l=0;
        l1=l2=0;
        r1=r2=-1;
        sum=0;
        scanf("%d%d",&n,&k);
        for(i=0;i<n;i++)
        scanf("%d",&a[i]);
        for(i=0;i<n;i++)
        {
            while(l1<=r1&&a[i]<a[deq1[r1]]) r1--;
            deq1[++r1]=i;
            while(l2<=r2&&a[i]>a[deq2[r2]])
            {
                //printf("%d %d %d!",i,a[i],deq2[r2]);
                r2--;    
            }
            deq2[++r2]=i;
            while(a[deq2[l2]]-a[deq1[l1]]>=k)
            {
                //printf("%d %d %d!\n",i,deq1[l1],deq2[l2]);
                if(deq1[l1]<deq2[l2])
                l=deq1[l1++]+1;
                else
                l=deq2[l2++]+1;
            }
            //printf("%d %d %d\n",i,deq1[l1],deq2[l2]);
            //if((a[deq1[l1]]-a[deq2[l2]]<=k))
            sum+=(i+1-l);
            //printf("%d %d %d\n",i,i+1-l,l);
        }
        printf("%I64d\n",sum);
    }
}

解法四:线段树(超时)
#include<stdio.h>#include<string.h>#include<iostream>#include<math.h> #include<time.h>#include<algorithm>using namespace std;int a[100010];int mx[100010][30];int rmq[100010][30];int Max,Min;struct node{    int l;int r;    int mn;int mx;}tree[400010];void init_tree(int left,int right,int pos){    int mid=(left+right)/2;    if(left==right)    {        tree[pos].mn=tree[pos].mx=a[left];        return;    }    init_tree(left,mid,pos*2);    init_tree(mid+1,right,pos*2+1);    tree[pos].mx=max(tree[pos*2].mx,tree[pos*2+1].mx);    tree[pos].mn=min(tree[pos*2].mn,tree[pos*2+1].mn);}void get(int le,int ri,int left,int right,int pos){    if(le==left&&ri==right)    {        Max=max(tree[pos].mx,Max);        Min=min(Min,tree[pos].mn);        return ;        //return tree[pos].mx-tree[pos].mn;    }    int mid=(left+right)/2;    if(ri<=mid)    get(le,ri,left,mid,pos*2);    else if(le>mid)    get(le,ri,mid+1,right,pos*2+1);    else {        get(le,mid,left,mid,pos*2);        get(mid+1,ri,mid+1,right,pos*2+1);    }}/*void init_rmq(int n){    int i,j;    for(i=0;i<n;i++)    rmq[i][0][1]=rmq[i][0][0]=a[i];//    for(i=n-1;i>=0;i--)//    {//        for(j=1;i+(1<<(j-1))<n;j++)//        //for(j=1;j<=25;j++)//        {//            rmq[i][j][0]=min(rmq[i][j-1][0]    ,rmq[i+(1<<(j-1))][j-1][0]);//            rmq[i][j][1]=max(rmq[i][j-1][11]    ,rmq[i+(1<<(j-1))][j-1][1]);    //        }//    }    for(j=1;(1<<j)<=n;j++)    {        for(i=0;i+(1<<j)-1<n&&i+(1<<(j-1))<n;i++)        {            rmq[i][j][0]=min(rmq[i][j-1][0],rmq[i+(1<<(j-1))][j-1][0]);            rmq[i][j][1]=max(rmq[i][j-1][1],rmq[i+(1<<(j-1))][j-1][1]);            }        }    }*//*int ask(int l,int r,int fg){    int exp=(int)(log(double(r-l+1))/log(2.0));    if(fg==1)    return max(rmq[l][exp][1],rmq[r-(1<<(exp))+1][exp][1]);    else     return min(rmq[l][exp][0],rmq[r-(1<<(exp))+1][exp][0]);}*/int main(){    //int start = clock();    int i,j,mid,k,m,t,ans,left,right,n;    long long sum;    scanf("%d",&t);    while(t--)    {        sum=0;        scanf("%d%d",&n,&k);        for(i=0;i<n;i++)        scanf("%d",&a[i]);                init_tree(0,n-1,1);    //    init_rmq(n);//        for(i=0;i<n;i++)//        {//            for(j=i;j<n;j++)//            printf("%d %d ,",ask(i,j,0),ask(i,j,1));//            printf("\n");//        }//        printf("%d %d %d\n",ask(0,3,1)-ask(0,3,0),ask(0,3,1),ask(0,3,0));//        printf("%d %d %d\n",ask(1,3,1)-ask(1,3,0),ask(1,3,1),ask(1,3,0));//        printf("%d %d %d\n",ask(2,3,1)-ask(2,3,0),ask(2,3,1),ask(2,3,0));        for(i=0;i<n;i++)        {            left=i;right=n-1;            while(left<=right)            {                mid=(left+right)/2;                //if(ask(i,mid,1)-ask(i,mid,0)<k)                Max=-1;                Min=2147483640;                get(i,mid,0,n-1,1);                if(Max-Min<k)                {//                    ans=mid;//                    left=mid+1;                    left=mid+1;                }                else right=mid-1;            }            sum+=left-i;            //sum+=ans-i;        }        printf("%I64d\n",sum);    }    //int end = clock();    //printf("%d ms\n", end - start);}还有跟高级的解法

http://www.cnblogs.com/names-yc/p/4665651.html  树状数组

http://www.cnblogs.com/andyqsmart/p/4665423.html (线段树)




                                             
0 0
原创粉丝点击