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

思路:

1.首先用数组存储所有的字符串;
2.我们通过计算可以得到一共有num=len/8*(n-1)个块,查询时如果超出编号范围输出-
3.我们记所有磁盘,条带号相同的部分组成一个区域,区域编号就按条带号,例如下图被分为三个区域:
在这里插入图片描述
4.如果块号为 b b b,则我们先推算出它在第 [ b ( n − 1 ) s ] [\frac{b}{(n-1)s}] [(n1)sb](从0开始编号)个区域( [ a ] [a] [a]代表不超过 a a a的最大整数),在这个区域里,它是第 b % ( n − 1 ) s b \% (n-1)s b%(n1)s个;设这个区域编号是 i i i,则这个区域校验位的 D s k Dsk Dsk号是 ( i + 1 ) ( n − 1 ) % n (i+1)(n-1)\%n (i+1)(n1)%n,因此我们可以得到块号为 b b b的块,它的 D s k Dsk Dsk号为 ( ( [ b ( n − 1 ) s ] + 1 ) ∗ ( n − 1 ) % n + b % ( ( n − 1 ) s ) s + 1 ) % n (([\frac{b}{(n-1)s}]+1)*(n-1)\%n+\frac{b\%((n-1)s)}{s}+1)\%n (([(n1)sb]+1)(n1)%n+sb%((n1)s)+1)%n;如果我们以 4 4 4个字节为一行(即 8 8 8个字符为一行),我们可以得到该块的行号为 s ∗ [ b ( n − 1 ) s ] + b % ( ( n − 1 ) s ) % s s*[\frac{b}{(n-1)s}]+b\%((n-1)s)\%s s[(n1)sb]+b%((n1)s)%s,我们令 r r r等于此行号,我们即要求该 D s k Dsk Dsk对应的字符串的substr(8*r,8)
5.如果不能直接求,需要异或求得,那我们就将所有其它磁盘对应位置的八个字符分别转换成十进制进行异或即可;

代码:

#include<bits/stdc++.h>
using namespace std;
int n,s,l,b,len,num;
string dsk[1005];
#define to_dec(c) (c>='0'&&c<='9'?c-'0':c-'A'+10)
#define to_hex(x) (x>=0&&x<=9?x+'0':x-10+'A')
void solve(){
    if(b>=num){cout<<"-\n";return;}
    int pos=b/((n-1)*s);
    int id=((pos+1)*(n-1)%n+b%((n-1)*s)/s+1)%n;
    int r=s*pos+b%((n-1)*s)%s;
    if(dsk[id].length()!=0){cout<<dsk[id].substr(r<<3,8)<<'\n';return;}
    if(n!=l+1){cout<<"-\n";return;}
    for(int i=0;i<8;i++){
        int x=-1;
        for(int j=0;j<n;j++){
            if(j==id)continue;
            if(~x)x^=to_dec(dsk[j][(r<<3)+i]);
            else x=to_dec(dsk[j][(r<<3)+i]);
        }
        cout<<(char)to_hex(x);
    }
    cout<<'\n';
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
//    freopen("Arutoria.txt","r",stdin);
    cin>>n>>s>>l;
    for(int i=0;i<l;i++){
        int id;cin>>id;
        cin>>dsk[id];len=dsk[id].length();
    }
    num=len/8*(n-1);
    int m;cin>>m;
    for(int i=0;i<m;i++){
        cin>>b;
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值