|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
//题意分析:https://blog.csdn.net/xienaoban/article/details/52164099
|
|
|
using namespace std;
|
|
|
|
|
|
//d:d块磁盘,s:1<=s<=64数据被划分成大小为s比特的数据块
|
|
|
//b:b个数据块 b in range(1,101)
|
|
|
int d, s, b, kase = 0;
|
|
|
//type:校验的种类E->偶校验 O->奇校验
|
|
|
char type;
|
|
|
|
|
|
//每块磁盘上(8的含义),数据的内容,之所以是8000,是因为每个字符是8个字节
|
|
|
char tab[8][8000];
|
|
|
|
|
|
//检查是不是合法
|
|
|
bool Fix() {
|
|
|
for (int i = 0; i < s * b; ++i) {
|
|
|
//s比特的数据块 * 数据块个数=所有的比特数据个数
|
|
|
// ++i 表示先加1,再循环,与i++的区别在于:
|
|
|
// https://blog.csdn.net/qq_41620518/article/details/88066963
|
|
|
int sum = 0, cnt = 0, x_no;
|
|
|
for (int j = 0; j < d; ++j) {
|
|
|
if (tab[j][i] == '1') ++sum;//求1的个数
|
|
|
if (tab[j][i] == 'x') ++cnt, x_no = j;
|
|
|
//如果存在x,即明确的错误标识,那么cnt记录错误的个数,同时记录是哪个位置出错了~
|
|
|
}
|
|
|
sum %= 2; //求最终校验位是0,还是1,看看是不是有问题
|
|
|
if (cnt >= 2) return false;//有两个以上错误就没办法了
|
|
|
else if (cnt == 1) //如果还可以挽救的话
|
|
|
{
|
|
|
if (sum)//如果是1
|
|
|
if (type == 'E') //如果是偶校验,表示缺少一个1,那么肯定是出错标识的那个位置是1
|
|
|
tab[x_no][i] = '1';
|
|
|
else tab[x_no][i] = '0';//如果是奇校验位,表示1的数量正常,出错标识那个的位置是0
|
|
|
else //如果是0
|
|
|
if (type == 'E') tab[x_no][i] = '0'; //如果是偶校验位,出错标识的那个位置是0
|
|
|
else tab[x_no][i] = '1';//如果是奇校验位,出错标识的那个位置是1
|
|
|
} else if (cnt == 0) {//没有明确出错标识,检查吧
|
|
|
if (type == 'E' && sum == 1) return false; //偶校验,但校验码是奇数,表示有错误
|
|
|
if (type == 'O' && sum == 0) return false; //奇校验,但校验码是偶数,表示有错误
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
//输出数据
|
|
|
void out_data() {
|
|
|
int sum = 0, bit_cnt = 0;
|
|
|
//b个数据块
|
|
|
for (int i = 0; i < b; ++i) {
|
|
|
int except = i % d; //排除哪一块磁盘上是存在parity
|
|
|
//d块磁盘
|
|
|
for (int j = 0; j < d; ++j) {
|
|
|
if (j == except) continue; //遍历每一块磁盘时,遇到校验块就跳过
|
|
|
//数据是s比特的数据块
|
|
|
//然后还有一点是输出数据的时候,4个bit转化为一个十六进制。
|
|
|
//刚开始做题认为每个数据块输出一个整数,这需要2^(5*64)这么大的数来存储,
|
|
|
//难道要用大整数类?后来一想,可以每一个十六进制位输出一次便可。
|
|
|
for (int k = i * s; k < i * s + s; ++k) { //遍历每一个数据位
|
|
|
bit_cnt = (bit_cnt + 1) % 4;
|
|
|
if (tab[j][k] == '0') sum *= 2;
|
|
|
else sum = sum * 2 + 1;
|
|
|
if (!bit_cnt) {
|
|
|
printf("%X", sum);
|
|
|
sum = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
//有尾巴需要输出的话
|
|
|
if (bit_cnt) {
|
|
|
int over = 4 - bit_cnt;
|
|
|
sum = sum * (1 << over);
|
|
|
printf("%X", sum);
|
|
|
}
|
|
|
printf("\n");
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
//https://www.cnblogs.com/cytus/p/7763569.html
|
|
|
//对于标准输入和输出的缓冲同步进行禁止,防止程序超时
|
|
|
ios::sync_with_stdio(false);
|
|
|
//真是能省就省啊,一路初始化数组,一般输入数据,如果数据是0或者小于0,那么停止。
|
|
|
while (memset(tab, 0, sizeof(tab)), cin >> d && d) {
|
|
|
//d:d个磁盘
|
|
|
//s:数据被划分成大小为s比特的数据块
|
|
|
//b: 1<=b<=100个数据块
|
|
|
//type:校验的种类,E表示偶校验,O表示奇校验
|
|
|
cin >> s >> b >> type;
|
|
|
for (int i = 0; i < d; ++i)
|
|
|
cin >> tab[i]; //在录入磁盘中的数据
|
|
|
//校验失败
|
|
|
if (!Fix())
|
|
|
printf("Disk set %d is invalid.\n", ++kase);
|
|
|
else {
|
|
|
//校验成功
|
|
|
printf("Disk set %d is valid, contents are: ", ++kase);
|
|
|
//输出数据
|
|
|
out_data();
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|