hdu3183 rmq求区间最值的下标

两个月前做的题,以后可以看看,是rmq关于求区间最值的下标

/*
hdu3183
终点 
给一个整数,可以删除m位,留下的数字形成一个新的整数 
rmq
取n-m个数,使形成的数最小
*/
#include<iostream>
#include<cstring>
#include<cmath> 
#include<cstdio>
#define MAXN 1010
using namespace std;
int dp[MAXN][20];
int a[MAXN];
void makeRMQ(int n,int b[]){//在i到1<<j区间内的最小值的下标 
    for(int i=0;i<n;i++)
        dp[i][0]=i;//区间长度等于0时 
    for(int j=1;(1<<j)-1<n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            if(b[dp[i][j-1]]<=b[dp[i+(1<<j-1)][j-1]])
            //这里一定要加等号,就是相等的时候取下标小的 
                dp[i][j]=dp[i][j-1];
            else
                dp[i][j]=dp[i+(1<<j-1)][j-1]; 
}
int rmqIndex(int s,int v,int b[]){//在区间s->v之间找区间最小值,
                                    //加等号,取小标小的 
    //1<<k+1的长度必须覆盖[s,v]    
    int k=(int)(log(v-s+1.0)/log(2.0));//k就是那个区间[s,v]长度的log2 
    if (b[dp[s][k]]<=b[dp[v-(1<<k)+1][k]])
        return dp[s][k];
    else
        return dp[v-(1<<k)+1][k]; 
} 
char str[MAXN];
int ans[MAXN]; 
int main(){
    int m;
    while(scanf("%s%d",&str,&m)!=EOF){
        int n=strlen(str);
        for(int i=0;i<n;i++)
            a[i]=str[i]-'0';
        makeRMQ(n,a);
        int t=0;
        int temp=0;//temp最后=n-m 
        //找n-m个数,每次从[t,i]中找到最小的 
        for(int i=m;i<n;i++){
            t=rmqIndex(t,i,a);
            ans[temp++]=a[t++];
        }
        t=0;
        while(t<temp&&ans[t]==0)
            t++;//=滤掉高位的0! 
        if(t>=temp)
            printf("0\n");
        else{
            for(int i=t;i<temp;i++)    
                printf("%d",ans[i]);
            printf("\n");
        }
    }
    return 0;
}

 

posted on 2018-12-03 09:51  zsben  阅读(323)  评论(0编辑  收藏  举报

导航