2015 多校赛 1002 (hdu 5289)

本文提供 HDU 5288 的四种解题思路,包括 RMQ 算法、单调队列及线段树等方法,并给出每种解法的 C++ 代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 (线段树)





                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值