poj5875 Function(st + 二分)

题目描述

传送门

就是给你n个数,m次询问,每一次询问给你[l,r]每次询问求出a[l] % a[l+1] % a[l+2] %……a[r] 的结果是多少

题目解析

每次有效的取模会使结果减半,因此只有log次有效取模,每次往右找一个不大于结果的最靠左的数,ST表+二分

注意RMQ查询的时候少用 log函数

Code

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
ll Min[maxn][33];
ll a[maxn];
int Log[maxn];
int n,m;
void GetLog(){
    Log[1]=0;
    for(int i=2;i<=n+1;i++){
        Log[i]=Log[i/2]+1;
    }
}
void RMQ(){
    for(int i=1;i<=n;i++){
        Min[i][0]=a[i];
    }
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<(j-1))<=n;i++){
            Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
        }
    }
}
ll query_min(int l,int r){
    int k=Log[r-l+1];
    return min(Min[l][k],Min[r-(1<<k)+1][k]);
}
int lower(int x,int y,int ans){
    int l=x,r=y,res=y+1;
    while(l<=r){
        int mid=(l+r)/2;
        if(query_min(x,mid)<=ans){
            res=mid;
            r=mid-1;
        }
        else{
            l=mid+1;
        }
    }
    return res;
}
int main(){
    int _;
    cin>>_;
    while(_--){
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        GetLog();
        RMQ();
        scanf("%d",&m);
        int x,y,l,r;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            ll ans=a[x];
            l=x+1,r=y; 
            while(l<=r&&ans){
                l=lower(l,r,ans);
                if(l<=r){
                    ans%=a[l];
                    l++;
                }
            }
            printf("%lld\n",ans);
        }
    }
}

 

posted @ 2021-09-13 00:24  lipu123  阅读(35)  评论(0)    收藏  举报