您的位置:首页 > 其它

HDU 3183 A Magic Lamp RMQ

2015-11-26 22:37 337 查看

题意:

给一串不含前导零的\(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\n");
else printf("%s\n", ans + st);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: