题目:A Magic Lamp
题目概述
时间限制:1秒 内存限制:128M
题目描述
一个整数(最多可以包含 1100 位数字。),删除 m m m( m < = m<= m<=整数的位数) 位数字,使剩余的数字最小(注:不能改变数字的顺序,要删除前导零,给定的整数将不包含前导零)。
(有若干组测试用例)。
样例输入
178543 4
1000001 1
100001 2
12345 2
54321 2
样例输出
13
1
0
123
321
解题思路
思路:用ST表找出保留的整数(保留的是必须要选出这个数的区间内最小的数)并输出。
- 循环输入各项数据
while(cin>>s>>m){
- ST表初始化
int len=s.size();
for(int i=0;i<len;i++){
min_f[i+1][0].first=s[i];
min_f[i+1][0].second=i+1;
}
- ST表打表。min_f[i][j]表示从i开始 2 j 2^j 2j个数位中的最小数。
for(int j=1;j<=log2(len);j++){
for(int i=1;i+pow(2,j)-1<=len;i++){
min_f[i][j]=min(min_f[i][j-1],min_f[i+(1<<j-1)][j-1]);
}
}
4.输出每一位,flag用来处理前导零,tmp是要保留的位数。
int tmp=s.size()-m;
int l=1,r=m+1;
bool flag=false;
while(tmp--){
int k=log2(r-l+1);
pair<char,int> ans=min(min_f[l][k],min_f[r-(1<<k)+1][k]);
if(ans.first!='0'){
flag=true;
}
if(flag){
cout<<ans.first;
}
l=ans.second+1;
r++;
}
if(!flag){
cout<<0;
}
cout<<endl;
AC代码
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
pair<char,int> min_f[1105][30];
string s;
int m;
void st(){
int len=s.size();
for(int i=0;i<len;i++){
min_f[i+1][0].first=s[i];
min_f[i+1][0].second=i+1;
}
for(int j=1;j<=log2(len);j++){
for(int i=1;i+pow(2,j)-1<=len;i++){
min_f[i][j]=min(min_f[i][j-1],min_f[i+(1<<j-1)][j-1]);
}
}
}
int main(){
while(cin>>s>>m){
st();
int tmp=s.size()-m;
int l=1,r=m+1;
bool flag=false;
while(tmp--){
int k=log2(r-l+1);
pair<char,int> ans=min(min_f[l][k],min_f[r-(1<<k)+1][k]);
if(ans.first!='0'){
flag=true;
}
if(flag){
cout<<ans.first;
}
l=ans.second+1;
r++;
}
if(!flag){
cout<<0;
}
cout<<endl;
}
return 0;
}
知识点:ST表
原理及简介
ST表是一种用来处理可重复贡献问题的特殊动态规划算法。
什么是可重复贡献问题呢?
就是一个元素多次参与答案的计算,不影响结果的问题就是可重复贡献问题。如:区间最大值,区间最小值,区间最小公倍数,区间最大公约数。
ST表的特别之处在于它的f[i][j]表示从编号为i的元素开始 2 j 2^j 2j个元素的最优答案。
状态转移方程: f [ i ] [ j ] = m i n ( f [ i ] [ j − 1 ] , f [ i + ( 1 < < j − 1 ) ] [ j − 1 ] ) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]) f[i][j]=min(f[i][j−1],f[i+(1<<j−1)][j−1])
它的状态转移方程是怎么来的呢?
就是把要求的区间平均分成两份,求两个区间的最终答案。
但要查的区间元素数往往不是2的次方,怎么办呢?
我们可以找出最接近并且小于的它的2的次方,然后把从头往后找那个2的次方个元素的最优值和从尾往前找那个2的次方个元素的最优值再求一遍最优就是正确答案。由于是可重复贡献问题,有重复部分也不怕。
代码实现
void st(){
int len=s.size();
for(int i=0;i<len;i++){
min_f[i+1][0].first=s[i];
min_f[i+1][0].second=i+1;
}
for(int j=1;j<=log2(len);j++){
for(int i=1;i+pow(2,j)-1<=len;i++){
min_f[i][j]=min(min_f[i][j-1],min_f[i+(1<<j-1)][j-1]);
//函数按实际情况替换
}
}
}
总结
这次我主要分享了题目:A Magic Lamp的解法,和ST表的相关信息。