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

思路:

1.首先用数组存储所有的字符串;
2.我们通过计算可以得到一共有num=len/8*(n-1)个块,查询时如果超出编号范围输出-
3.我们记所有磁盘,条带号相同的部分组成一个区域,区域编号就按条带号,例如下图被分为三个区域:
在这里插入图片描述
4.如果块号为bb,则我们先推算出它在第[b(n1)s][\frac{b}{(n-1)s}](从0开始编号)个区域([a][a]代表不超过aa的最大整数),在这个区域里,它是第b%(n1)sb \% (n-1)s个;设这个区域编号是ii,则这个区域校验位的DskDsk号是(i+1)(n1)%n(i+1)(n-1)\%n,因此我们可以得到块号为bb的块,它的DskDsk号为(([b(n1)s]+1)(n1)%n+b%((n1)s)s+1)%n(([\frac{b}{(n-1)s}]+1)*(n-1)\%n+\frac{b\%((n-1)s)}{s}+1)\%n;如果我们以44个字节为一行(即88个字符为一行),我们可以得到该块的行号为s[b(n1)s]+b%((n1)s)%ss*[\frac{b}{(n-1)s}]+b\%((n-1)s)\%s,我们令rr等于此行号,我们即要求该DskDsk对应的字符串的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;
}

posted @ 2019-12-09 14:03  YuhanのBlog  阅读(200)  评论(0编辑  收藏  举报