题意:
给一串不含前导零的(n)个数字,要删去(m(m leq n))个数字,要使剩下的数字最小。
分析:
删去(m)个数字就相当于选(n-m)个数字,因为最终选出来的数字的长度是一定的,所以第一个数字越小越好。
第一个数字只能在区间([1,m+1])中选,否则后面的就不够选了。
假设我们选在了位置(p),那么第二个数字就在区间([p+1, m+2])中选,以此类推。
因此RMQ中我们要查询的是最小值的最左下标。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 10;
char s[maxn], ans[maxn];
int n, m;
int d[maxn][11];
int Min(int i, int j) { return s[i] <= s[j] ? i : j; }
void init() {
for(int i = 0; i < n; i++) d[i][0] = i;
for(int j = 1; (1 << j) <= n; j++) {
for(int i = 0; i + (1<<j) - 1 < n; i++) {
d[i][j] = Min(d[i][j-1], d[i + (1<<(j-1))][j-1]);
}
}
}
int query(int L, int R) {
int k = 0;
while((1 << (k+1)) <= R - L + 1) k++;
return Min(d[L][k], d[R-(1<<k)+1][k]);
}
int main()
{
while(scanf("%s", s) == 1) {
n = strlen(s);
scanf("%d", &m);
init();
int choose = -1;
for(int i = 0; i < n - m; i++) {
choose = query(choose + 1, m + i);
ans[i] = s[choose];
}
ans[n - m] = 0;
int st;
for(st = 0; st < n - m; st++) if(ans[st] > '0') break;
if(st >= n - m) printf("0
");
else printf("%s
", ans + st);
}
return 0;
}