机试刷题Day2 rmq+二分

题目链接: 点击打开链接
代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int a[maxn],q_max[maxn][50],q_min[maxn][50];
int n,k;

void rmq(){
    for(int j=0; (1<<j)<=n; j++){
        for(int i=1;i<=n;i++){
            if(j==0){
                q_max[i][0] = q_min[i][0] = a[i];
            }
            else {
                if(i+(1<<j)-1 <= n){
                    q_max[i][j] = max(q_max[i][j-1], q_max[i+(1<<(j-1))][j-1]);
                    q_min[i][j] = min(q_min[i][j-1], q_min[i+(1<<(j-1))][j-1]);
                }
            }
        }
    }
}

int Q(int l, int r, bool is_q_max){
    int kk=0;
    while(l+(1<<(kk+1))-1 <= r) kk++;
    if(is_q_max == true)return max(q_max[l][kk],q_max[r-(1<<kk)+1][kk]);
    else return min(q_min[l][kk],q_min[r-(1<<kk)+1][kk]);
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1; i<=n; i++){
            scanf("%d",&a[i]);
        }
        rmq();
        long long ans=0;
        for(int i=1; i<=n; i++){
            if(Q(i,n,true)-Q(i,n,false) < k) {ans+=(n-i+1);continue;}

            int l=i, r=n, mid;
            while(l<r-1){
                mid = (l+r)>>1;
                if(Q(i,mid,true)-Q(i,mid,false) >= k) r = mid;
                else l = mid;
            }
            ans += (l-i+1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

wa两次,因为没用long long
复习一下rmq。dp[i][j]表示从i开始的2^j长度中的最值。由此可列出转移方程。代码里有。


稍微改了一下,这个更好一点
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 100005;
int a[maxn],q_max[maxn][50],q_min[maxn][50];
int n,k;

void rmq(){
    for(int j=0; (1<<j)<=n; j++){
        for(int i=1;i<=n;i++){
            if(j==0){
                q_max[i][0] = q_min[i][0] = a[i];
            }
            else {
                if(i+(1<<j)-1 <= n){
                    q_max[i][j] = max(q_max[i][j-1], q_max[i+(1<<(j-1))][j-1]);
                    q_min[i][j] = min(q_min[i][j-1], q_min[i+(1<<(j-1))][j-1]);
                }
                else break;
            }
        }
    }
}

int Q(int l, int r, bool is_q_max){
    int kk = (int)(log(1.0*(r-l+1))/log(2.0));
    if(is_q_max == true)return max(q_max[l][kk],q_max[r-(1<<kk)+1][kk]);
    else return min(q_min[l][kk],q_min[r-(1<<kk)+1][kk]);
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1; i<=n; i++){
            scanf("%d",&a[i]);
        }
        rmq();
        long long ans=0;
        for(int i=1; i<=n; i++){
            if(Q(i,n,true)-Q(i,n,false) < k) {ans+=(n-i+1);continue;}

            int l=i, r=n, mid;
            while(l<r-1){
                mid = (l+r)>>1;
                if(Q(i,mid,true)-Q(i,mid,false) >= k) r = mid;
                else l = mid;
            }
            ans += (l-i+1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值