C++RMQ算法—————A Magic Lamp

本文介绍了一道关于使用C++解决旅行者Kiki遇到的问题,她需要找到一种方法,从一个长整数中删除m个数字,使得剩余数字组成的整数最小。该问题可以转化为求数列中删去m个元素后的最小值,通过RMQ算法来求解。文章详细讲解了思路,并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

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? 

输入:

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. 

输出:

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

样例输入:

178543 4 
1000001 1
100001 2
12345 2
54321 2

样例输出:

13
1
0
123
321

思路分析:

其实这一题就是求数列删出后的最小值。

我们可以先用RMQ求出数列区间的最小值。

之后我们要取len-m个数,那么我们的第一个区间边界就是1到m+1,为什么呢。

我们要取len-m个数,那么就算是后面的都取,则是len-m+1,所以区间就是[1,m+1]。

最后我们在寻找过程中用暴力就可以寻找下一个节点的左端点(所寻的数的位置)。

代码实现:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int len,n,m,dp[1005][25],s1[1005];
char s[1005];
int Get_quary(int l,int r)
{
	int k=(int)(log(double(r-l+1))/log(double(2)));
	return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int main()
{
	while(scanf("%s%d",s,&m)!=-1)
	{
	    len=strlen(s);
		int tot=0;
		if(m<=0)
		{
			puts(s);
			continue;
		}
		for(int i=0;i<len;i++)
			dp[i][0]=s[i]-'0';
		for(int j=1;(1<<j)<=len;j++)
            for(int i=0;i+(1<<j)-1<len;i++)
                dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
        int l=0,r=m;
        while(l<=r)
        {
        	int p=Get_quary(l,r);
        	tot++;
        	s1[tot]=p;
        	int i=l;
        	for(;i<=r;i++)
        		if(p+'0'==s[i])
        			break;
        	l=i+1;
        	r++;
		}
		int i;
		for(i=1;i<tot;i++)
			if(s1[i]>0)
				break;
        if(i==tot)
        {
            printf("0\n");
            continue;
        }
		for(;i<tot;i++)
			printf("%d",s1[i]);
		printf("\n");
		memset(dp,0,sizeof(dp));
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值