rmq-st算法<区间最大最小>(hdu 5875)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5875

题意:给定一个数组,并给出[l,r],要求求出A(l)%A(l+1)%......%A(r)的值,当l==r时 直接等于A(l)

题解:这道题的意思就是每次找到区间内最靠近l的且比当前ans小的进行取模,每次都这么取,知道到r,可以利用rmq算法先用o(nlogn)进行预处理,然后查找时的复杂度就只有o(1),每次快速查找最靠近的最小值

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;
int dp[100050][25];
void rmq(int num)//o(nlogA)
{
    for(int j=1;(1<<j)<=num;j++)
    {
        for(int i=1;i<=num;i++)
        {
            if(i+(1<<j)-1<=num)
            {
                dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
            }
        }
    }
}
int query(int l,int r)
{
    if(l>r) return 1000000005;
    int len=r-l+1;
    int k=0;
    while((1<<(k+1))<=len) k++;
    return min(dp[l][k],dp[r-(1<<(k))+1][k]);
}
int main()
{
    int t,m,q;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&dp[i][0]);
        }
        rmq(m) ;
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            int ans=dp[l][0];
            bool flag=0;
            if(l==r) {printf("%d\n",ans);continue;};
            l++;
            while(l<=r)
            {
                int left=l,right=r;
                while(left<right)
                {
                    int mid=(left+right)/2;
                    if(query(left,mid)<=ans) right=mid;
                    else if(query(mid+1,right)<=ans) left=mid+1;
                    else {flag=1;break;}
                }
                if(flag) break;
                l=left;
                ans%=dp[l][0];
                l++;//必须加1,不然可以取自己
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

附录:

rmq-st算法:http://blog.csdn.net/niushuai666/article/details/6624672/

              http://blog.csdn.net/liang5630/article/details/7917702


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值