这个题还是CSP第三题的老样子,特别难读。
题目简述:
他讲的是啊,现在有那么一个RAID系统,这个系统有n块硬盘(0 ~ n-1),每块硬盘都要分块(学过操作系统的话应该都知道),一块是4个字节,然后呢有一些原因,他引入了一个叫做条带的东西。然后询问m次,让输出对应物理块的内容。其中可能丢了几块硬盘。
大小关系:
RAID系统 > 硬盘 > 条带 > 块
(即,一个系统由多个硬盘组成,一个硬盘由多个条带组成,一个条带由多个块组成。)
什么是条带?
刚刚不是说每个硬盘分块了吗,然后从0开始标号,这个条带就是连续的多个块,比如说一个条带是2块,那么0号条带就是这个硬盘的0 ~ 7字节,1号条带就是8 ~ 15字节 (每个条带两块,所以一个条带8字节)。
什么是冗余备份条带?
就是刚刚不是说n个硬盘吗,那么他们分别都有0号条带,1号条带,2号条带 。。。
对吧,所以现在有n个0号条带,这n个0号条带中,有n-1个是用来存储数据的,另外的那一个是用来冗余备份的,怎么冗余备份呢,就是其余n-1个的0号条带异或和。
同理,n个1号条带中也有n-1个存储数据,1个备份
然后,对于n个x号条带,具体哪个盘的x号条带作为冗余备份呢?他是这样规定的,首先第n号盘的做,然后n-1做,。。。然后0号盘做,然后n号盘的做。可以根据下图理解。红色的就是冗余条带。(这个图没划分块,每个格子是一个条带)
询问中硬盘的块号怎么确定?
这个问题的话最好还是看第2个样例的图,编号是从选中的冗余盘,往后依次填写编号的。
这个图不同于上边那个,这个虚线部分就是条带内的分块情况。
丢失硬盘怎么办?
通过异或的性质(1.交换律,2. 相同数异或结果为0)可以得知,如果系统丢失了一个盘,那么可以通过其他盘的异或得出来这块盘,如果少两个盘及以上,就没办法了。
如何查询?
首先输入了块号 q 之后,我们可以得知当前他所属的条带号,假设条带大小为s。
所属条带号 tid = q/s;
那么这个条带是该硬盘的第几号条带呢 ,通俗来说他在这个图中的哪一行呢?
hang = 条带号 /(n-1); 也就是tid / (n-1)
现在就是确定他在哪个盘了对吧,我们需要先计算出来冗余盘是哪个
很明显 冗余盘 rid = (n-1) - (行%n);
是哪块硬盘就是rid往后数 条带号%(n-1)+1个
bid = rid +(条带号%(n-1)+1);
那么这个再知道这个块在条带内往后偏移了多少就可以了,也就是q%s 。
(注意:如果是唯一缺失的盘。要从其他盘的异或结果得到)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 1005;
string C[MAXN];
int vis[MAXN],n,s,l,len;
int Xor(int now,int c)
{
if(c>='0' && c<='9')c -= '0';
if(c>='A' && c<='Z')c -= 'A',c+=10;
return now^c;
}
char itoc(int now)
{
if(now >= 0 && now<=9)now+='0';
if(now >= 10 && now<=15)now-=10,now+='A';
return (char)now;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>s>>l;
for(int i=0;i<n;i++)C[i] = "";
for(int i=1;i<=l;i++){
int id;
cin>>id; vis[id] = 1;
cin>>C[id];
if(len == 0)len = C[id].size();
}
int dis = 0,dis_cnt = 0;
for(int i=0;i<n;i++){
if(!vis[i]){
dis = i; dis_cnt ++;
}
}
int m;
cin>>m;
while(m--)
{
int q;
cin>>q;
int tid = q/s;
int hang = tid/(n-1);
int rid = (n-1)-(hang%n);
int bid = (rid + (tid%(n-1)) + 1)%n;
int off = q%s;
int st_add = hang*s*8;
st_add += off*8;
if( (dis_cnt >1&&!vis[bid]) || (st_add>=len) ){
cout<<"-\n";
continue;
}
if(bid == dis){
string pri = "";
for(int i=st_add;i<st_add+8;i++){
int now = 0;
for(int j = 0;j<n;j++){
if(j == dis)continue;
now = Xor(now,C[j][i]);
}
pri += char(itoc(now));
}
cout<<pri<<endl;
continue;
}
for(int i=st_add;i<st_add+8;i++){
cout<<C[bid][i];
}
cout<<"\n";
}
}
/*
2 1 2
0 000102030405060710111213141516172021222324252627
1 000102030405060710111213141516172021222324252627
2
0
1
3 2 2
0 000102030405060710111213141516172021222324252627
1 A0A1A2A3A4A5A6A7B0B1B2B3B4B5B6B7C0C1C2C3C4C5C6C7
2
2
5
*/