Let’s design a data structure
A
A
A that combines arrays and linked lists as the following:
At the very beginning, an integer array
A
0
A_0
A0 of length
L
0
L_0
L0 is initialized for the user. When the user tries to access the
i
i
ith element
A
[
i
]
A[i]
A[i], if
0
≤
i
<
L
0
0≤i<L_0
0≤i<L0, then
A
[
i
]
A[i]
A[i] is just
A
0
[
i
]
A_0[i]
A0[i]. Now our system is supposed to return
h
0
+
i
×
s
i
z
e
o
f
(
i
n
t
)
h_0+i×sizeof(int)
h0+i×sizeof(int) as the accessed address, where
h
0
h_0
h0 is the initial address of
A
0
A_0
A0, and
s
i
z
e
o
f
(
i
n
t
)
sizeof(int)
sizeof(int) is the size of the array element, which is simply int, taking 4 bytes.
In case there is an overflow of the user’s access (that is, i ≥ L 0 i≥L_0 i≥L0), our system will declare another array A 1 A_1 A1 of length L 1 L_1 L1. Now A [ i ] A[i] A[i] corresponds to A 1 [ j ] A_1[j] A1[j] (It’s your job to figure out the relationship between i i i and j j j). If 0 ≤ j < L 1 0≤j<L_1 0≤j<L1, then h 1 + j × s i z e o f ( i n t ) h_1+j×sizeof(int) h1+j×sizeof(int) is returned as the accessed address, where h 1 h_1 h1 is the initial address of A 1 A_1 A1.
And if there is yet another overflow of the user’s access to A 1 [ j ] A_1[j] A1[j], our system will declare another array A 2 A_2 A2 of length L 2 L_2 L2, and so on so forth.
Your job is to implement this data structure and to return the address of any access.
Input Specification:
Each input file contains one test case. For each case, the first line gives 2 positive integers
N
(
≤
1
0
4
)
N (≤10^4)
N(≤104) and
K
(
≤
1
0
3
)
K (≤10^3)
K(≤103) which are the number of arrays that can be used, and the number of user queries, respectively.
Then
N
N
N lines follow, each gives 2 positive integers, which are the initial address (
≤
1
0
7
≤10^7
≤107) and the length (
≤
100
≤100
≤100) of an array, respectively. The numbers are separated by spaces. It is guaranteed that there is no overlap of the spaces occupied by these arrays.
Finally, K K K indices of the elements queried by users are given in the last line. Each index is an integer in the range [ 0 , 2 20 ] [0,2^{20}] [0,220].
Output Specification:
For each query, print in a line the accessed address. If the queried index exceeds the range of all the
N
N
N arrays, output Illegal Access
instead, and this query must NOT be processed.
Print in the last line the total number of arrays that have been declared for the whole process.
Sample Input:
6 7
2048 5
128 6
4016 10
1024 7
3072 12
9332 10
2 12 25 50 28 8 39
Sample Output:
2056
4020
1040
Illegal Access
3072
140
3116
5
Hint
A
[
2
]
A[2]
A[2] is just
A
0
[
2
]
A_0[2]
A0[2], so the accessed address is
2048
+
2
×
4
=
2056
2048+2×4=2056
2048+2×4=2056.
In order to access
A
[
12
]
A[12]
A[12], declaring
A
1
A_1
A1 is not enough, we need
A
2
A_2
A2 with initial address
h
2
=
4016
h_2=4016
h2=4016. Since
A
[
12
]
=
A
2
[
1
]
A[12]=A_2[1]
A[12]=A2[1], the accessed address is
4016
+
1
×
4
=
4020
4016+1×4=4020
4016+1×4=4020.
In order to access
A
[
25
]
A[25]
A[25], we need
A
3
A_3
A3 with initial address
h
3
=
1024
h_3=1024
h3=1024. Since
A
[
25
]
=
A
3
[
4
]
A[25]=A_3[4]
A[25]=A3[4], the accessed address is
1024
+
4
×
4
=
1040
1024+4×4=1040
1024+4×4=1040.
The access of
A
[
50
]
A[50]
A[50] exceeds the maximum boundary of all the arrays, and hence an illegal access. There is no extra array declared.
In order to access
A
[
28
]
A[28]
A[28], we need
A
4
A_4
A4 with initial address
h
4
=
3072
h_4=3072
h4=3072. Since
A
[
28
]
=
A
4
[
0
]
A[28]=A_4[0]
A[28]=A4[0], the accessed address is just
3072
3072
3072.
It is clear to see that
A
[
8
]
=
A
1
[
3
]
A[8]=A_1[3]
A[8]=A1[3] and hence the accessed address is
128
+
3
×
4
=
140
128+3×4=140
128+3×4=140; and
A
[
39
]
=
A
4
[
11
]
A[39]=A_4[11]
A[39]=A4[11] so the accessed address is
3072
+
11
×
4
=
3116
3072+11×4=3116
3072+11×4=3116.
All together there are 5 arrays used for the above queries.
Caution:
这次考试说实话不难,不过第一题就是通过率最低的题,当时我写完后只对了两个测试点,退出去后看四个题的通过率,好家伙,后三个题都是 0.5 左右,只有第一题 0.0 几(到结束的时候,这道题通过率也只有0.04),于是信心一下子上来了,去写后面三个题的时候都是一遍 AC。
这道题我觉得有两个容易错的,第一个就是绊倒很多人——默认开的数组个数是 1 不是 0,因为题目中有这样一句话:
At the very beginning, an integer array A 0 A_0 A0 of length L 0 L_0 L0 is initialized for the user.
所以就算一次有效查询也没有,开的数组个数也是 1 而不是 0。
第二个容易理解错的是这个开的数组个数 tmpCnt 的更新规则不是当开了一个新的数组的话 tmpCnt 就加 1,而是假如你第一次查询就查到了第 5 个数组(这里数组下标从 1 开始记),那么你的 cnt 就是 5 而不是 2,因为你查到第 5 个数组的过程是:首先看到超过了第一个数组的范围,然后开第 2 个数组,一看仍然超了,然后开第 3 个,以此类推,而不是一看是在第五个数组范围内,所以就直接开辟第五个数组,因此 tmpCnt 的更新规则是:
tmpCnt = max(tmpCnt, l + 1);
// l 是通过二分确定的访问元素所在数组的位置
代码思路就是 arrayAddress
存放每个数组的起始地址,jieshuweizhi
存放每个数组的最后一个元素在整个数据结构里对应的下标,然后输入一个访问位置后首先看是不是在合法范围内,然后在 jieshuweizhi
里二分找到第一个大于这个访问位置的元素,得到就是访问的元素所在数组的位置,然后计算相应地址并输出。
Solution:
// Talk is cheap, show me the code
// Created by Misdirection 2021-09-11 13:32:51
// All rights reserved.
#include <iostream>
#include <vector>
using namespace std;
int arrayAddress[10010];
int jieshuweizhi[10010];
bool flag[10010];
int main(){
int n, k;
// n - the number of arrays that can be used
// k - the number of user queries
scanf("%d %d", &n, &k);
for(int i = 0; i < n; ++i){
int address, cnt;
scanf("%d %d", &address, &cnt);
arrayAddress[i] = address;
if(i == 0) jieshuweizhi[i] = cnt - 1;
else jieshuweizhi[i] = jieshuweizhi[i - 1] + cnt;
}
int tmpCnt = 1;
flag[0] = true;
for(int i = 0; i < k; ++i){
int tmp;
scanf("%d", &tmp);
if(tmp > jieshuweizhi[n - 1]){
printf("Illegal Access\n");
continue;
}
int l = 0, r = n - 1;
while(l < r){
int mid = l + r >> 1;
if(jieshuweizhi[mid] >= tmp) r = mid;
else l = mid + 1;
}
if(l == 0) printf("%d\n", arrayAddress[l] + tmp * 4);
else printf("%d\n", arrayAddress[l] + 4 * (tmp - jieshuweizhi[l - 1] - 1));
if(!flag[l]){
tmpCnt = max(tmpCnt, l + 1);
flag[l] = true;
}
}
printf("%d\n", tmpCnt);
return 0;
}