• 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: 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 }


  • 相关阅读:
    用Python操纵文件(自动化脚本的第一步)
    关于Numpy Array的使用技巧整理
    有用的在线小工具汇总
    HackerRank刷题之路---Python
    周志华老师《机器学习》复习要点(持续更新)
    Python函数式编程学习笔记
    Supervised Descent Method学习之路(持续更新)
    HackerRank刷题之路之---Algorithm(基于Python2)(持续更新)
    Vim常用命令精简化汇总及Vim的相关配置问题
    在VC++6.0中,如何将多个工程添加到同一个工作区?
  • 原文地址:https://www.cnblogs.com/Stomach-ache/p/3703133.html
Copyright © 2020-2023  润新知