HDU 3183 A Magic Lamp (RMQ+贪心)

Description:

Kiki likes traveling. One day she finds a magic lamp, unfortunately the genie in the lamp is not so kind. Kiki must answer a question, and then the genie will realize one of her dreams.
The question is: give you an integer, you are allowed to delete exactly m digits. The left digits will form a new integer. You should make it minimum.
You are not allowed to change the order of the digits. Now can you help Kiki to realize her dream?

Input

There are several test cases.
Each test case will contain an integer you are given (which may at most contains 1000 digits.) and the integer m (if the integer contains n digits, m will not bigger then n). The given integer will not contain leading zero.

Output

For each case, output the minimum result you can get in one line.
If the result contains leading zero, ignore it.

Sample Input

178543 4 
1000001 1
100001 2
12345 2
54321 2

Sample Output

13
1
0
123
321

对于一个n位数,删除m个位后,得到的最小数是什么,比如12345 2,删除两个位,得到最小的就是123.。模拟了半天复杂度也是没超过各种细节也处理了就是一直wa,然后一直没想到是RMQ,

具体就是我们要删除m个数,令res=n-m,这样就变成了要取res个数,问题就变成了从n个数中取res个数,使得组合成的数字最小,且从左到右,那么我们要怎么取呢?下面举例说明:比如54321这组数据,我们要取3个数字使得组合成的数字最小,那么第一个数取的最大范围就是在543中取(从第一个位置开始取),因为要保证至少是个三位数,所以至少要留两位,我们取得3,接下来就是从3这个位置取 取2个数字且保证这两个数字组合成的两位数最小,同样的,我们至少要留一位,所以取2,就这样重复同样的过程,用一个循环就能解决了,当然还要注意的是,我们需要得到这个数的位置,比如我们第一次取3之后,我们从哪开始取呢?这就需要3这个数所在的位置了,我们在ST表算法中用dp[i][j]记录的是位置,比较的是此位置的字符大小!

AC代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iomanip>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double ld;
const int INF = 0x3f3f3f3f;
int dp[1005][50];
using namespace std;
int n;
char str[1005];
void init()
{
    memset(dp, INF, sizeof dp );
    for (int i=0; i<n; i++)
        dp[i][0]=i;
    for (int j=1; (1<<j)<=n; j++)
    {
        for(int i=0; i+(1<<j)-1<n; i++)
        {
            if(str[dp[i][j-1]]<=str[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 rmq(int l, int r)
{
    int k=(int)(log2(r-l+1));
    if(str[dp[l][k]]<=str[dp[r-(1<<k)+1][k]])
        return dp[l][k];
    else
        return dp[r-(1<<k)+1][k];
}

int main()
{
    while(~scanf("%s",str))
    {
        n=strlen(str);
        init();
        int m;
        scanf("%d",&m);
        if(m>=n)
        {
            printf("0\n");
            continue;
        }
        int res=n-m;
        int ans[1005];
        int cnt=0;
        int l=0;
        int r=n-res;
        while(res--)
        {
            ans[cnt++]=rmq(l,r);
            l=ans[cnt-1]+1;
            r=n-res;
        }
        int i=0;
        while(str[ans[i]]=='0'&&i!=cnt-1)
        {
            i++;
        }
        for(;i<cnt;i++)
        {
            printf("%c",str[ans[i]]);
        }
        printf("\n");
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值