solution.md 3.3 KB
Newer Older
每日一练社区's avatar
每日一练社区 已提交
1 2 3 4 5 6
# 压缩变换


**问题描述**

小明最近在研究压缩算法。  
每日一练社区's avatar
每日一练社区 已提交
7

每日一练社区's avatar
每日一练社区 已提交
8
他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比。  
每日一练社区's avatar
每日一练社区 已提交
9

每日一练社区's avatar
每日一练社区 已提交
10
然而,要使数值很小是一个挑战。  
每日一练社区's avatar
每日一练社区 已提交
11

每日一练社区's avatar
每日一练社区 已提交
12
最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面出现的数字很大可能是刚出现过不久的数字。对于这种特殊的序列,小明准备对序列做一个变换来减小数字的值。  
每日一练社区's avatar
每日一练社区 已提交
13

每日一练社区's avatar
每日一练社区 已提交
14
变换的过程如下:  
每日一练社区's avatar
每日一练社区 已提交
15

每日一练社区's avatar
每日一练社区 已提交
16
从左到右枚举序列,每枚举到一个数字,如果这个数字没有出现过,刚将数字变换成它的相反数,如果数字出现过,则看它在原序列中最后的一次出现后面(且在当前数前面)出现了几种数字,用这个种类数替换原来的数字。  
每日一练社区's avatar
每日一练社区 已提交
17

每日一练社区's avatar
每日一练社区 已提交
18
比如,序列(a1, a2, a3, a4, a5)=(1, 2, 2, 1, 2)在变换过程为:  
每日一练社区's avatar
每日一练社区 已提交
19

每日一练社区's avatar
每日一练社区 已提交
20
a1: 1未出现过,所以a1变为-1;  
每日一练社区's avatar
每日一练社区 已提交
21

每日一练社区's avatar
每日一练社区 已提交
22
a2: 2未出现过,所以a2变为-2;  
每日一练社区's avatar
每日一练社区 已提交
23

每日一练社区's avatar
每日一练社区 已提交
24
a3: 2出现过,最后一次为原序列的a2,在a2后、a3前有0种数字,所以a3变为0;  
每日一练社区's avatar
每日一练社区 已提交
25

每日一练社区's avatar
每日一练社区 已提交
26
a4: 1出现过,最后一次为原序列的a1,在a1后、a4前有1种数字,所以a4变为1;  
每日一练社区's avatar
每日一练社区 已提交
27

每日一练社区's avatar
每日一练社区 已提交
28
a5: 2出现过,最后一次为原序列的a3,在a3后、a5前有1种数字,所以a5变为1。  
每日一练社区's avatar
每日一练社区 已提交
29

每日一练社区's avatar
每日一练社区 已提交
30 31 32 33 34 35
现在,给出原序列,请问,按这种变换规则变换后的序列是什么。  


**输入**

输入第一行包含一个整数n,表示序列的长度。  
每日一练社区's avatar
每日一练社区 已提交
36

每日一练社区's avatar
每日一练社区 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
第二行包含n个正整数,表示输入序列。  


**输出**

输出一行,包含n个数,表示变换后的序列。  


**输入例子 1**

```
5
1 2 2 1 2
```

**输出例子 1**

```
-1 -2 0 1 1
```

**输入例子 2**

```
12
```

**输出例子 2**

```
-1 0 -2 -3 1 1 2 2 0 0 2 2
```

以下程序实现了这一功能,请你补全空白处的内容:

每日一练社区's avatar
每日一练社区 已提交
72
```c
每日一练社区's avatar
每日一练社区 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 5;
int a[maxn], tree[maxn << 2];

int n, maxpoint;

void init()
{
    maxpoint = 1;
    while (maxpoint < n)
        maxpoint <<= 1;
    memset(tree, 0, sizeof(tree));
    memset(a, 0, sizeof(a));
}

void update(int k, int addnum)
{
    k += maxpoint - 1;
    tree[k] += addnum;
    while (k)
    {
        k = (k - 1) >> 1;
        tree[k] += addnum;
    }
}

int query(int a, int b, int k, int l, int r)
{
    if (a == b || (r <= a || l >= b))
        return 0;
    if (a <= l && r <= b)
        return tree[k];
    else
    {
        int mid = (l + r) >> 1;
        return __________________;
    }
}

int main()
{
    int temp;
    map<int, int> mp;
    cin >> n;
    init();
    for (int i = 0; i < n; i++)
    {
        cin >> temp;
        if (mp.count(temp))
        {
            int pre = mp[temp];
            a[i] = query(pre + 1, i, 0, 0, maxpoint);
            update(pre, -1);
        }
        else
        {
            a[i] = -temp;
        }
        mp[temp] = i;
        update(i, 1);
    }
    for (int i = 0; i < n; i++)
        cout << a[i] << " ";
    return 0;
}
```

## 答案

每日一练社区's avatar
每日一练社区 已提交
144
```c
每日一练社区's avatar
每日一练社区 已提交
145 146 147 148 149 150 151
query(a, b, (k << 1) + 1, l, mid) + query(a, b, (k + 1) << 1, mid, r)
```

## 选项

### A

每日一练社区's avatar
每日一练社区 已提交
152
```c
每日一练社区's avatar
每日一练社区 已提交
153 154 155 156 157
query(a, b, (k >> 1) + 1, l, mid) + query(a, b, (k + 1) >> 1, mid, r)
```

### B

每日一练社区's avatar
每日一练社区 已提交
158
```c
每日一练社区's avatar
每日一练社区 已提交
159 160 161 162 163
query(a, b, k << 1, l, mid) + query(a, b, k << 1, mid, r)
```

### C

每日一练社区's avatar
每日一练社区 已提交
164
```c
每日一练社区's avatar
每日一练社区 已提交
165 166
query(a, b, (k << 1) + 1, l, mid) + query(a, b, (k + 1) >> 1, mid, r)
```