hdu 3183 RMQ 应用

题目大意是,给你一个1000位的数,要你删掉m个为,求结果最小数。

思路:在n个位里面删除m个位,也就是找出n-m个位组成最小数

 

所以在区间 [0, m]里面找最小的数,对应的下标标号i

接着找区间 [i+1,m++]里面的最小数,对于下标为ii

接着找区间 [ii+1,m++]里面的最小数……

这样就会找n-m个数了。区间这样安排的目的是为了保证取出来的数的顺序。

#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 1111
#define MAXN 500
#define MAXM 500
int dp[M][30];
int dp2[MAXN][MAXM][10][10];
int l[M],r[M],a[M];
char s[1002];
/*
*一维RMQ ST算法
*构造RMQ数组 makermq(int n,int b[]) O(nlog(n))的算法复杂度
*dp[i]j] 表示从i到i+2^j -1中最大的一个值
*dp[i][j]=max{dp[i][j-1],dp[i+2^(j-1)][j-1]}
*查询RMQ rmq(int s,int v)
*将s ->v 分成两个2^k的区间
*即 k=(int)log2(s-v+1)
*查询结果应该为 max(dp[s][k],dp[v-2^k+1][k])
*/
int check(int i,int j)
{
    return a[i]<=a[j]?i:j;
}
int rmq(int s,int v)
{
    int k=(int)(log((v-s+1)*1.0)/log(2.0));
    return check(dp[s][k],dp[v-(1<<k)+1][k]);
}
void makermq(int n,int b[])
{
    int i,j;
    for(i=1;i<=n;i++)
        dp[i][0]=i;
    for(j=1;(1<<j)<=n;j++)
        for(i=1;i+(1<<j)-1<=n;i++)
            dp[i][j]=check(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}

/*
*二维RMQ ST算法
*构造RMQ数组 makermq(int n,int m,int b[][]) O(n*m*log(n)*log(m))算法复杂度
*dp2[row][col][i][j] 表示 行从row ->row +2^i-1 列从col ->col +2^j-1 二维区间里最大值
*dp2[row][col][i][j] = 下行
*max{dp2[row][col][i][j-1],dp2[row][col][i-1][j],dp2[row][col+2^(j-1)][i][j-1],dp2[row+2^(i-1)][col][i-1][j]}
*查询RMQ rmq(int sx,int ex,int sy,int ey)
*同一维的将sx->ex 分为两个2^kx区间 将 sy->ey分为两个2^ky的区间
*kx=(int)log2(ex-sx+1) ky=(int)log2(ey-sy+1)
*查询结果为
*max{dp2[sx][sy][kx][ky],dp2[sx][ey-2^ky+1][kx][ky],dp2[ex-2^kx+1][sy][kx][ky],dp2[ex-2^kx+1][ey-2^ky+1][kx][ky]}
*/

void makermq(int n,int m,int b[][MAXM])
{
    int row,col,i,j;
    for(row=1;row<=n;row++)
        for(col=1;col<=m;col++)
            dp2[row][col][0][0]=b[row][col];
    for(i=0;(1<<i)<=n;i++)
        for(j=0;(1<<j)<=m;j++)
        {
            if(i==0&&j==0) continue;
            for(row=1;row+(1<<i)-1<=n;row++)
                for(col=1;col+(1<<j)-1<=m;col++)
                {
                if(i==0)
                    dp2[row][col][i][j]=max(dp2[row][col][i][j-1],dp2[row][col+(1<<(j-1))][i][j-1]);
                else
                    dp2[row][col][i][j]=max(dp2[row][col][i-1][j],dp2[row+(1<<(i-1))][col][i-1][j]);
                }
        }
}
int rmq(int sx,int ex,int sy,int ey)
{
int kx=(int)(log((ex-sx+1)*1.0)/log(2.0)),ky=(int)(log((ey-sy+1)*1.0)/log(2.0));
return max(max(dp2[sx][sy][kx][ky],dp2[sx][ey-(1<<ky)+1][kx][ky]),max(dp2[ex-(1<<kx)+1][sy][kx][ky],dp2[ex-(1<<kx)+1][ey-(1<<ky)+1][kx][ky]));
}
int main()
{
    int u,v,n,q,m;
    //freopen("//media/学习/ACM/input.txt","r",stdin);
    while(scanf("%s%d",s,&n)!=EOF)
    {
        int i,j,len=strlen(s);
        for(i=0;i<len;i++)a[i+1]=s[i]-'0';
        makermq(len,a);
        m=len-n;
        q=i=1,j=n+1;
        while(m--)
        {
            i=rmq(i,j);
            l[q++]=a[i++];
            j++;
        }
        for(i=1;i<q;i++)
        if(l[i])break;
        if(i==q){puts("0");continue;}
        for(j=i;j<q;j++)cout<<l[j];cout<<endl;
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值