CCF-CSP 201903-3 损坏的RAID5(模拟)

大模拟。ios

思路:算法

  首先要求出所求数据在哪块硬盘,哪一个数据块上。数组

  思路是观察题目中给出的插图(彩色部分是另外加的):测试

  给出RAID块编号block,可直接求出硬盘条带的编号strip(图中红色数字)k(图中蓝色数字)、硬盘数据块的编号blkui

  接下来求块block所在的硬盘编号disk,但题目引入“校验盘P”增长了实现的难度。spa

  为了简化问题,不妨先求出校验盘P所在的硬盘编号“Disk n”,记为np,因而其它硬盘的位置就能够根据np和 该硬盘与校验盘P的相对位置offset求出(以图中k=1为例,strip 3与P相对位置为一、strip 2与P的相对位置为2)。code

  到这里,咱们求出了硬盘编号disk、硬盘数据块的编号blk,能够肯定所求数据的绝对位置。以上模拟寻址的代码集中在Line 36~43。blog

 

  接下来经过disk判断目标数据是否位于现存的硬盘中:接口

    若是是,则直接从给出的硬盘读取数据;ip

    若是不在现存的硬盘中,再判断可否经过给出的硬盘还原数据:分析发现,可以还原离线硬盘数据的充分条件是:阵列中现存硬盘数L仅比硬盘总数N小1。

      若是能还原,按照题目给出的冗余算法恢复数据便可;

      若是不能还原,输出减号`-`。

 

遇到的坑有:

1.题目中所指出的“硬盘数据大小 40KiB”指的是原始数据的大小,不是测试集中给出的16进制字符串的大小。

由于硬盘原始数据的长度是其对应16进制表示的字符串长度的1/2(不考虑空格)。若是采用静态存储类型的数组放置字符串,其元素个数不该少于3*40KiB。

 

2.本题具备大量I/O,容易在I/O消耗大量时间,形成超时。

解决这个问题时须要明确,当数据规模很大时,stdio与iostream两种I/O方式的效率存在明显差别。存在以下两种状况:

1. ios::sync_with_stdio(true)(系统默认)

  这种状况下标准库会在内部同步iostream与stdio两种接口的状态。所以引入了iostream向stdio同步的额外开销,这时stdio效率略高于iostream

 

2. ios::sync_with_stdio(false)

  手动关闭了上述同步。这时iostream与stdio状态独立,这就避免了iostream额外的开销,使得iostream效率高于stdio

  这是由于iostream的cin/cout的目标数据类型是在编译时就能肯定的,相比之下scanf/printf还须要在运行时动态解析数据类型,引入额外的开销。

 

综上,使用"C++风格"的iostream,设置ios::sync_with_stdio(false),iostream效率高于stdio。

 

AC的代码以下:

 1 /*
 2  * 1.  stdio与iostream混合使用,iostream内部存在与stdio同步的开销,致使超时。
 3  *    解决办法,统一使用iostream,设置ios::sync_with_stdio(false); 
 4  *    此时cin/cout快于scanf,printf。 
 5  * 2. 使用scanf, printf,耗时多于iostream(未关闭流同步)。 
 6  * 3. 题目中所指出的“硬盘数据大小 40KiB”指的是原始数据的大小,不是16进制字符串的大小!!
 7  * 4. CSP彷佛将可执行文件的加载时间也计算在总时间内。若在.bss开辟过大的数组,加载耗时过多,超时。
 8  *    “空间换时间”并不绝对可行。 
 9  */
10 #include <iostream>
11 #include <cstdio>
12 #include <string>
13 #include <cstring>
14 
15 #define N_DISK 1000+1
16 #define T_PER_BLK 8
17 
18 using namespace std;
19 
20 typedef unsigned int uint_t;
21 
22 string ds[N_DISK];
23 size_t ds_len;
24 string buff;
25 uint_t N, S, L;
26 
27 inline uint_t toint(char h) {
28     return h>='0'&&h<='9'?h-'0':h-'A'+10;
29 }
30 
31 inline char tohex(uint_t d) {
32     return d<=9?d+'0':d+'A'-10;
33 }
34 
35 void read(uint_t block) {
36     uint_t stripe = block/S;
37     uint_t k = stripe / (N-1);
38     uint_t np = N-(k%N) -1;
39     uint_t offset = stripe - k * (N-1);
40     uint_t disk = (np+offset+1)%N;
41     
42     uint_t blk = k*S + (block%S);
43     uint_t blk_offset = blk*T_PER_BLK;
44     
45     buff = '-';
46     
47     if (blk_offset+T_PER_BLK <= ds_len) {
48         if (!ds[disk].empty()) {
49             cout << ds[disk].substr(blk_offset, T_PER_BLK) << endl;
50             return;
51         
52         } else if (N-L == 1) {
53             buff = "00000000";
54             for(uint_t i=0; i<N; i++) {
55                 if (i==disk) continue;
56                 
57                 for(uint_t j=0; j<T_PER_BLK; j++) {
58                     buff[j] = tohex(toint(ds[i][blk_offset+j]) ^ toint(buff[j])); 
59                 }
60             }
61         }
62     }
63     
64     cout << buff << endl;
65 }
66 
67 int main(void) {
68     ios::sync_with_stdio(false);
69     cin >> N >> S >> L;
70 
71     uint_t disk_id;
72     for(uint_t i=0; i<L; i++) {
73         cin >> disk_id;
74         cin >> ds[disk_id];
75     }
76     ds_len = ds[disk_id].length();
77     
78     int M;
79     cin >> M;
80     for(int i=0; i<M; i++) {
81         uint_t block;
82         cin >> block;
83         
84         read(block);
85     }
86     
87     return 0;
88 }
相关文章
相关标签/搜索