CCF CSP 201903-3 损坏的RAID5(模拟)
思路:
1.首先用数组存储所有的字符串;
2.我们通过计算可以得到一共有num=len/8*(n-1)
个块,查询时如果超出编号范围输出-
;
3.我们记所有磁盘,条带号相同的部分组成一个区域,区域编号就按条带号,例如下图被分为三个区域:
4.如果块号为,则我们先推算出它在第(从0开始编号)个区域(代表不超过的最大整数),在这个区域里,它是第个;设这个区域编号是,则这个区域校验位的号是,因此我们可以得到块号为的块,它的号为;如果我们以个字节为一行(即个字符为一行),我们可以得到该块的行号为,我们令等于此行号,我们即要求该对应的字符串的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;
}