HDU 3183 A Magic Lamp

来源:互联网 发布:淘宝 电脑版 编辑:程序博客网 时间:2024/05/20 21:21

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183

A Magic Lamp

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1763    Accepted Submission(s): 692


Problem 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 1100001 212345 254321 2
 

Sample Output
1310123321
 
题目大意:给你一个大整数,长为n,叫你抠掉m个使得剩下的n-m个数最小(原来的顺序不可以改变)。例如178543抠掉4个数,剩下的最小的数为13,其实可以把题目的意思转化为,在长度为n的大整数中取n-m个数,使这n-m个数字按原来的顺序拼成的整数最小,显然每次取得时候应该取最小的数了,由抽屉原理可知,选取的第一个数必然在

[0,m]这个长度为m+1的区间内,也可以用反证法证明,若第一个数在[m+1,n-1]这个区间内,那之后最多能选取n-1-(m+2)+1=n-m-2,事实上我们还差n-m-1个数,所以,原假设不成立。设取出来的第一个数位置为x,则同理,第二个数必然在[x+1,m+1]这个区间里,同样地第三个数在[x',m+2],,,,一直到最后一个数。现在我们要解决的问题是要在[x'+1,m+i](i对应取第i-1个数)这个区间里取一个最小的数,这就是RMQ问题(Range mini query)。可以用线段树实现,不过基于线段树的RMQ创建的复杂度为o(n*log(n))查询复杂度为o(log(n)),而基于稀疏表(ST)的创建复杂度为o(n*log(n)),但查询复杂度为o(1),是一个在线算法。一般如果对区间有更新的话,我们就用线段树,不更新的话用ST算法比较高效。

ST算法是基于动态规划思想实现的。其状态转移方程为dp[i][j]=min(dp[i][j-1],dp[i+(j-1)^2][j-1]),其dp[i][j]代表从i点起长度为2^j的区间的最小(大)值

而查询的话只需要算出能覆盖它的最小区间的最值就可以了。为min(dp[l][((int)log2(len))],dp[r+1-2^((int)log2(len))][(int)log2(len)]);

具体算法设计分析过程可以参考博文http://blog.csdn.net/liang5630/article/details/7917702,此处不再赘述。

AC代码如下

#include<cstdio>#include<cmath>#include<cstring>const int maxn=100005;int dp[maxn][30],m;char s[maxn],ans[maxn];int Min(int i,int j) { return s[i]<=s[j]?i:j;}void InitRMQ(int n){    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++)        dp[i][j]=Min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}int RMQ(int l,int r){    int k=(int)(log((r-l+1)*1.0)/log(2.0));    return Min(dp[l][k],dp[r-(1<<k)+1][k]);}int main(){    while(~scanf("%s%d",s,&m))    {        int x=0,pa=0,n=strlen(s),pb;        InitRMQ(n);//创建ST表        for(int i=0;i<(n-m);i++) x=RMQ(x,m+i),ans[pa++]=s[x++];        for(pb=0,ans[pa]='\0';ans[pb]=='0';pb++);        if(pa==pb) printf("0\n");        else printf("%s\n",ans+pb);    }    return 0;}


0 0
原创粉丝点击