CSP 201903-3 损坏的RAID5

本文介绍了一种基于RAID5的数据恢复算法,通过将硬盘分为多个条带,每个条带包含校验位,实现数据冗余。文章详细解析了算法流程,并提供了AC代码示例,适用于最大40KB数据长度的场景。

题目链接:戳这里

题意:
有n个硬盘,把n个硬盘分成许多个条带,每个条带含有s个块,按照 RAID5 的规则,即每一行的条带中都会有一个条带负责校验,它的值是其他条带的异或和。把数据存放在n个硬盘中,求第temp块上存储的数据。
注意:最大的数据长度为40KB,数据中每两个字符组成一个字节,因此数组需要开到80000。

这题题意很难读,好在第二个样例给出了图,可以对着那个图模拟。

下面本人ac代码,很多地方写的都挺麻烦。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <stack>
using namespace std;
const int maxn = 1e3 + 10;
char st[maxn][80000+5];
bool vis[maxn];
int main() {
    int n, s, l, m, len;
    scanf("%d %d %d", &n, &s, &l);
    int temp = -1;
    for(int i = 0; i < l; ++i) {
        scanf("%d ", &temp);
        fgets(st[temp],85000,stdin);
        vis[temp] = 1;
    }
    len = strlen(st[temp]);
    scanf("%d", &m);

    while(m--) {
        int row = 1, col = 0;
        scanf("%d", &temp);

        if(temp >= (len / 8) * (n-1) ) {//如果超出范围,直接输出
            puts("-"); continue;
        }
        while(row * (n-1) * s <= temp) {//判断在哪一行
            ++row;
        }
        --row;

        col = ((n - row) + (temp - row * (n - 1) * s) / s) % n;//判断在哪个磁盘

        int offset = (temp - row * (n - 1) * s) % s;//判断在磁盘的具体那一部分

        int block = row * s + offset;


        if(vis[col]) {
            for(int i = 0; i < 8; ++i) {
                printf("%c", st[col][i + block * 8]);
            }
            printf("\n");
        } else if(n - l == 1){
            for(int i = 0; i < 8; ++i) {
                int ans = 0;
                char c;
                for(int j = 0; j < n; ++j) {
                    if(j == col) continue;
                    c = st[j][i + block * 8];

                    if(c >= '0' && c <= '9') ans ^= int(c -'0');
                    else ans ^= int(c - 'A') + 10;
                   // printf("1ans : %d\n", ans);
                }
                if(ans > 9) printf("%c", char('A'+ans - 10));
                else printf("%c", char(ans+'0'));

            }
            printf("\n");
        } else {
            puts("-");
        }
    }
    return 0;
}
/*
2 1 2
0 000102030405060710111213141516172021222324252627
1 000102030405060710111213141516172021222324252627
3
0
1
2

3 2 2
0 000102030405060710111213141516172021222324252627
1 A0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7
13
0
1
2
3
4
5
6
7
8
9
10
11
12

3 2 1
0 000102030405060710111213141516172021222324252627
3
0
1
2

4 2 2
0 000102030405060710111213141516172021222324252627
1 A0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7
13
0
1
2
3
4
5
6
7
8
9
10
11
12
*/

在对 该博客 进行学习后,对本人代码进行改进得:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <stack>
using namespace std;
const int maxn = 1e3 + 10;
char st[maxn][80000+5];
bool vis[maxn];
int main() {
    int n, s, l, m, len;
    scanf("%d %d %d", &n, &s, &l);
    int temp = -1;
    for(int i = 0; i < l; ++i) {
        scanf("%d ", &temp);
        fgets(st[temp],85000,stdin);
        vis[temp] = 1;
    }
    len = strlen(st[temp]);
    scanf("%d", &m);

    while(m--) {
        int row = 1, col = 0;
        scanf("%d", &temp);

        if(temp >= (len / 8) * (n-1)) {//如果超出范围,直接输出
            puts("-"); continue;
        }
        int band = temp / s;//条带号
        row = band / (n - 1);//磁盘的某一个条带
        col = ((n - row) + (temp - row * (n - 1) * s) / s) % n;//判断在哪个磁盘

        int offset = temp % s;//条带的具体那一块

        int block = row * s + offset; //磁盘的具体那一块


        if(vis[col]) {
            for(int i = 0; i < 8; ++i) {
                printf("%c", st[col][i + block * 8]);
            }
            printf("\n");
        } else if(n - l == 1){
            for(int i = 0; i < 8; ++i) {
                int ans = 0;
                char c;
                for(int j = 0; j < n; ++j) {
                    if(j == col) continue;
                    c = st[j][i + block * 8];

                    if(c >= '0' && c <= '9') ans ^= int(c -'0');
                    else ans ^= int(c - 'A') + 10;
                   // printf("1ans : %d\n", ans);
                }
                if(ans > 9) printf("%c", char('A'+ans - 10));
                else printf("%c", char(ans+'0'));

            }
            printf("\n");
        } else {
            puts("-");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值