HDU 4217

点击打开题目链接

题型就是数据结构。给一个数组,然后又k次操作,每次操作给定一个数ki, 从数组中删除第ki小的数,要求的是k次操作之后被删除的所有的数字的和。 

简单的思路就是,用1标记该数没有被删除,0表示已经被删除,对于找到第ki小的数, 只需要找到标记数组中第一个前缀和为ki的下标,又因为用来标记的数组的前缀和是不减数列,所以可以用二分来加速。这里值得注意的是,被删除后的数,不会第二次或者多次被找到,即每个数最多被找到一次,因为如果该数被删除了,而且该数所在下标的前缀和是ki,那么一定还存在一个更小的下标,使得它的前缀和也是ki, 而我们要找的就是第一次出现前缀和为ki的下标。还需要使用I64.


附上代码:

 1 /*************************************************************************

 2     > File Name: 4217.cpp

 3     > Author: Stomach_ache

 4     > Mail: [email protected]

 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\n", cnt++, ans);

90         }

91 

92         return 0;

93 }

 


 

你可能感兴趣的:(HDU)