uva11235 frequent values(Sparse Table)

题目链接:https://vjudge.net/problem/UVA-11235

题意:

给一个非降序的整数数组a,求[i, j]中出现最多次数的数,出现了几次。

思路:

明显的是RMQ问题。白书上用的是Sparse Table,这个叫ST表就变成了表表….

一开始思路就被定死,求出现最多的数出现的次数,感觉无从下手。看到刘汝佳的做法,还有这种操作….先进行游程编码,把相同的数压缩成一个点,对于所求的区间[i, j],那么i和j所对应的a[i]和a[j]必然属于某个对应的压缩后的点,对这些压缩后的点建树就可以了,维护最大值。

先判断i和j对应的区间是否相同,相同的话,答案就是j-i+1
否则为max( right[idx[i]] - i +1, j - left[idx[j]] +1, RMQ(idx[i]+1, idx[j]-1) )
idx[i]表示i所在的区间号,left为该区间的开始位置,right为该区间的结束位置。

竟然1A…

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

const int maxn = 1e6 + 1000;
int x, y, tmp;
int num[maxn], lf[maxn], rg[maxn], val[maxn], cnt[maxn];

class SparseTable{
public:
    int **d, n, m;
    SparseTable(){}
    ~SparseTable(){
        for(int i=0; i<n; ++i) 
            delete []d[i];
        delete []d;
    }

    int cal_len(int n){
        return (int)(log(n*1.0)/log(2.0));
    }

    void init(int A[], int n){
        this->n = n;
        m = cal_len(n) + 200;
        d = new int*[n];
        for(int i=0; i<n; ++i) d[i] = new int[m];
        for(int i=0; i<n; ++i) d[i][0] = A[i];
        for(int j=1; (1<<j)<=n; ++j){
            for(int i=0; i+(1<<j)-1<n; ++i){
                d[i][j] = max(d[i][j-1], d[i+(1<<(j-1))][j-1]);   // minimal or maximal
            }
        }
    }

    int RMQ(int L, int R){
        int k = 0;
        while((1<<(k+1)) <= R-L+1) ++k;
        return max(d[L][k], d[R-(1<<k)+1][k]); // minimal or maximal
    }
};


int main(){
    int n, q;
    ios::sync_with_stdio(false);
    while(cin>>n){
        if(n==0) break;
        cin>>q;
        int pre=-maxn, tot=-1;
        memset(num, 0, sizeof(num));
        memset(lf, 0, sizeof(lf));
        memset(rg, -1, sizeof(rg));
        memset(val, 0, sizeof(val));
        memset(cnt, 0, sizeof(cnt));
        for(int i=0; i<n; ++i){
            cin>>tmp;
            if(tmp!=pre){
                ++tot;
                val[tot] = tmp;
                cnt[tot]++;
                if(i-1>=0) rg[i-1] = i-1;
                lf[i] = i;
                pre = tmp;
            }
            else{
                cnt[tot]++;
                lf[i] = lf[i-1];
            }
            num[i] = tot;
        }
        rg[n-1] = n-1;
        for(int i=n-2; i>=0; --i){
            if(rg[i]==-1) rg[i] = rg[i+1];
        }

        SparseTable ST;
        ST.init(cnt, tot+1);
        for(int i=0; i<q; ++i){
            cin>>x>>y;
            --x; --y;
            int no1 = num[x];
            int no2 = num[y];
            if(no1==no2){
                cout<<y-x+1<<endl;
            }
            else{
                int ans1 = rg[x] - x + 1;
                int ans2 =  y - lf[y] + 1;
                int ans3;
                if(num[x]+1>num[y]-1){
                    ans3 = 0;
                }
                else{
                    ans3 = ST.RMQ(num[x]+1, num[y]-1);  
                }
                cout<<max(max(ans1, ans2), ans3)<<endl;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值