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 }
相關文章
相關標籤/搜索