题型就是数据结构。给一个数组,然后又k次操作,每次操作给定一个数ki, 从数组中删除第ki小的数,要求的是k次操作之后被删除的所有的数字的和。
简单的思路就是,用1标记该数没有被删除,0表示已经被删除,对于找到第ki小的数, 只需要找到标记数组中第一个前缀和为ki的下标,又因为用来标记的数组的前缀和是不减数列,所以可以用二分来加速。这里值得注意的是,被删除后的数,不会第二次或者多次被找到,即每个数最多被找到一次,因为如果该数被删除了,而且该数所在下标的前缀和是ki,那么一定还存在一个更小的下标,使得它的前缀和也是ki, 而我们要找的就是第一次出现前缀和为ki的下标。还需要使用I64.
附上代码:
1 /************************************************************************* 2 > File Name: 4217.cpp 3 > Author: Stomach_ache 4 > Mail: sudaweitong@gmail.com 5 > Created Time: 2014年04月26日 星期六 21时51分19秒 6 > Propose: HDU 4217 7 ************************************************************************/ 8 //BIT + BinarySearch 复杂度 O(k * logn * logn) 9 //单点更新,区间求值, 用1表示该数没有被删除,0表示该数已经被删除 10 #include <cmath> 11 #include <string> 12 #include <vector> 13 #include <cstdio> 14 #include <fstream> 15 #include <cstring> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 20 #define X first 21 #define Y second 22 #define MAX_N (262144 + 5) 23 typedef long long LL; 24 typedef pair<int, int> pii; 25 int n, k; 26 int c[MAX_N]; 27 28 int 29 lowbit(int x) { 30 return x & (-x); 31 } 32 33 LL 34 get_sum(int x) { 35 LL s = 0; 36 while (x > 0) { 37 s += c[x]; 38 x -= lowbit(x); 39 } 40 41 return s; 42 } 43 44 void 45 update(int x, int v) { 46 while (x <= n) { 47 c[x] += v; 48 x += lowbit(x); 49 } 50 51 return ; 52 } 53 54 int 55 main(void) { 56 int T, cnt = 1; 57 scanf("%d", &T); 58 while (T--) { 59 scanf("%d %d", &n, &k); 60 memset(c, 0, sizeof(c)); 61 for (int i = 1; i <= n; i++) { 62 update(i, 1); 63 } 64 LL ans = 0; 65 for (int i = 0; i < k; i++) { 66 int ki; 67 scanf("%d", &ki); 68 //只需要找到前缀和为ki对应的数,也就是第ki小的数 69 //此处为不减数列,所以使用二分来找到第一个前缀和为ki对应的数 70 int L = ki, R = n, tmp = L; 71 while (L <= R) { 72 int mid = L + (R - L) / 2; 73 int s = get_sum(mid); 74 if (s < ki) { 75 L = mid + 1; 76 } else { 77 if (s == ki) { 78 tmp = mid; 79 } 80 R = mid; 81 } 82 if (tmp == L && tmp == R) { 83 break; 84 } 85 } 86 ans += tmp; 87 update(tmp, -1); 88 } 89 printf("Case %d: %I64d ", cnt++, ans); 90 } 91 92 return 0; 93 }