Loading

HDU 3183:A Magic Lamp(RMQ)

http://acm.hdu.edu.cn/showproblem.php?pid=3183

题意:给出一个数,可以删除掉其中m个字符,要使得最后的数字最小,输出最后的数字(忽略前导零)。

思路:设数的长度为n,那么我们要删除其中m个最大的字符,可以转化为我们保留其中的n-m个最小的字符。对于第一个数,它存在的区间必定在[1,m+1]里面,因为我们要保证后面[m+2,n]区间有n-m-1个字符。当找到第一个数的下标为tmp的时候,第二个数的区间就是[tmp+1,m+2]……以此类推,直到找到最后。

这里我们就可以用RMQ来处理了。dp数组保存的信息是下标。

注意最后可能有前导零,要去除掉前导零。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7 #define N 50010
 8 char s[1010];
 9 int dp[1010][20];
10 int ans[1010];
11 int n, m;
12 
13 void Init() {
14     int k = (int)(log(n) / log(2));
15     for(int i = 1; i <= n; i++) dp[i][0] = i;
16     for(int j = 1; j <= k; j++)
17         for(int i = 1; i + (1 << j) - 1 <= n; i++)
18             if(s[dp[i][j-1]] <= s[dp[i+(1<<(j-1))][j-1]]) dp[i][j] = dp[i][j-1];
19             else dp[i][j] = dp[i+(1<<(j-1))][j-1];
20 }
21 
22 int Query(int l, int r) {
23     int k = (int)(log(r - l + 1) / log(2));
24     return s[dp[l][k]] <= s[dp[r-(1<<k)+1][k]] ? dp[l][k] : dp[r-(1<<k)+1][k];
25 }
26 
27 int main() {
28     while(~scanf("%s%d", s + 1, &m)) {
29         n = strlen(s + 1);
30         Init();
31         int cnt = 0, tmp = 1;
32         for(int i = 1; i <= n - m; i++) {
33             tmp = Query(tmp, m + i);
34             ans[++cnt] = s[tmp++] - '0';
35         }
36         for(tmp = 1; tmp <= cnt; tmp++) if(ans[tmp] != 0) break;
37         if(tmp > cnt) puts("0");
38         else { for(; tmp <= cnt; tmp++) printf("%d", ans[tmp]); puts(""); }
39     }
40     return 0;
41 }

 

posted @ 2017-01-24 16:17  Shadowdsp  阅读(166)  评论(0编辑  收藏  举报