HDU - 3183 A Magic Lamp
题目
给一个最多 1000 位的整数,去掉 n 个数位,使剩下的数字尽可能小。
分析
去掉 n 个数位之后剩下的数位是固定的,之后对于高位贪心的尽可能取最小值即可。可以用RMQ预先处理最小值的下标。不过如果值相同,优先级左边的要比右边的高。剩下的数位有可能比较大,按字符串输出即可。
#include <bits/stdc++.h>
#define d(x) cout << (x) << endl;
using namespace std;
const int N = 1e4 + 10;
string a;
int num[N];
int st[N][20];
int n, m;
void rmq() // 预处理最小值下标
{
for (int i = 1; i <= m; i++){
st[i][0] = i;
}
for (int j = 1; (1<<j) <= m; j++){
for(int i = 1; i + (1<<j)-1 <= m; i++){
int a = st[i][j - 1];
int b = st[i + (1 << (j - 1))][j - 1];
st[i][j] = num[a] <= num[b] ? a : b;
}
}
}
int ask(int l, int r) //查询
{
int k = log2(r - l + 1);
int a = st[l][k];
int b = st[r - (1 << k) + 1][k];
return num[a] <= num[b] ? a : b; // 相同时,优先左边的
}
void solve()
{
int s = 1; // 每次查询左端点
int e = n + 1; // 每次查询右端点
int k = m - n; // 查询次数
int flag = 0; // 前导零
while(k--){
int t = ask(s, e);
if(flag || num[t]){
cout << num[t];
flag = 1;
}
s = t+1; // 更新左端点
e++; // 更新右端点
}
if(!flag){
cout << "0";
}
cout << endl;
}
int main()
{
while(cin >> a >> n){
m = a.length();
for(int i = 0; i < m; i++){
num[i + 1] = a[i] - '0';
}
rmq();
solve();
}
return 0;
}