CCF201903-3损坏的RAID5C++实现满分

原题链接

 


正文开始

在开始做题前我们先复习一下题目中提到的变量

/**
*	n	表示总的磁盘数
*	s	阵列的条带大小
*	l	现存的磁盘数目
*	m	待读取的块数
*	disklenth	该变量表示一个磁盘包含的块数,题目中并没有提出,在这里提出方便后面的计算
*/

前四个变量调一下顺序看着怎么觉得不对劲啊 滑稽
 
要做这个题首先要读懂题目意思,这个题目又臭又长,废话多,要在漫长的文字中寻找有用的信息的确是一件考验耐心的事。简单来说,这个题的意思就是给定考生一个块号,然后用程序计算出该块上的内容。

块在磁盘上的存储规则

在了解阵列存储规则之前先定义两个结构体

typedef struct Disk
{
	int disknum;//磁盘号
	string content;//磁盘上的内容
}Disk;//磁盘结构体

typedef struct
{
	int disknum;//块所在的磁盘号,如下图所示第六个块的disknum为0
	int posi;//该块在所在磁盘中的位置,如下图所示第六个块的posi为2
}Block;//块结构体

Disk disk[1005];//用于存储存在的磁盘的磁盘号和该磁盘上的内容 
int block[1005];//用于存储待查询的块的块号 

例: 如下的RAID5阵列由三个磁盘组成,每个条带包含两个块(用虚线隔开的一个长方形表示一个块,连续两个长方形组成的一个正方形表示一个条带)每个磁盘有六个块。
在这里插入图片描述
现在开始探索规则,为了方便描述,做一下规定,以每个磁盘为一列,磁盘上条带号相同的条带为一行。如上图阵列可分为三行三列。

1、要先计算出所求块所在的行号,可由下式得到:

bandnum=blknum/(s*(n-1));//blknum为块号

如上图块号为6的行号为1。
 

2、每一行上校验条带所在的磁盘号可由下式算出:

db=n-1-bandnum%n;//db为一行中该行校验条带所在的磁盘号

如上图第一行的校验条带所在的磁盘号为1。
 
3、一行中的起始存储块所在的磁盘号为:db+1,则由此得一个块所在磁盘的磁盘号为:

diskn=(db+1+blknum%(s*(n-1))/s)%n;//diskn为一个块所在磁盘的磁盘号

 
4、一个块在所在磁盘中的位置为:

pos=bandnum*s+blknum%s;//pos为一个块在所在磁盘中的位置

 


经过以上步骤我们已经得到了一个块在阵列中的确切位置,接下来就到了输出该块的内容了。
一个磁盘的容量为:

disklenth=disk[0].content.size()/8

一个阵列的最大容量为:

max=disklenth*(n-1)

1、若块号大于等于max,块超出阵列总长度,输出“-”;
2、若块号不超过max,在disk[ ]中查找该块所在的磁盘号是否存在disk[ ]中,若存在直接读出输出即可;
3、若该块所在的磁盘号不在在disk[ ]中,则说明该磁盘遗失,需要其他磁盘异或得到结果。但若n-1>l,则由于磁盘数太少不能异或得到结果输出"-"。若n-1=l则可由其它磁盘异或得到结果。
(第三步涉及字符串转整型,大体思路就是先把字符串转为数字,然后数字进行异或,输出异或后的结果)

代码

#include <iostream>
#include <string>
using namespace std;

typedef struct Disk
{
	int disknum;
	string content;
}Disk;

typedef struct
{
	int disknum;
	int posi;
}Block;

int n,s,l,m,disklenth;
Disk disk[1005];//用于存储存在的磁盘的磁盘号和该磁盘上的内容 
int block[1005];//用于存储待查询的块的块号 

Block getPosition(int blknum);//获取块在磁盘上的位置 
int sixteenPower(int power);//计算16的power次幂 
int hextoDec(char c);//将16进制字符c转化成十进制数字 
int stringtoInt(string str);//将16进制字符串str转化成十进制整型数字 
void print(int blknum);//打印块号为blknum的块的内容 

int main()
{
	std::ios::sync_with_stdio(false);
	cin>>n>>s>>l;
	for(int i=0;i<l;i++)//存现存的磁盘 
	{
		cin>>disk[i].disknum;
		cin>>disk[i].content;
	}
	disklenth=disk[0].content.size()/8;
	cin>>m;
	for(int i=0;i<m;i++)
		cin>>block[i];
	for(int i=0;i<m;i++)
		print(block[i]);	
	return 0;	
}

Block getPosition(int blknum)
{
	int bandnum,diskn,pos,b;
	bandnum=blknum/(s*(n-1));//该块所在的行号 
	b=blknum%(s*(n-1));
	int db=n-1-bandnum%n;//db为一行中该行校验条带所在的磁盘号 
	int i=0;
	diskn=(db+1+blknum%(s*(n-1))/s)%n;//该块所在的磁盘号 
	pos=bandnum*s+blknum%s;//该块在磁盘上的位置 
	Block block;
	block.disknum=diskn;
	block.posi=pos; 
	return block;
}

int sixteenPower(int power)
{
	if(power==0)
		return 1;
	int res=1;
	for(int i=0;i<power;i++)
		res*=16;
	return res;
}

int hextoDec(char c)
{
	int ans;
	switch(c)
	{
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':ans=c-'0';break;
		case 'a':
		case 'A':ans=10;break;
		case 'b':
		case 'B':ans=11;break;
		case 'c':
		case 'C':ans=12;break;
		case 'd':
		case 'D':ans=13;break;
		case 'e':
		case 'E':ans=14;break;
		case 'f':
		case 'F':ans=15;break;
	}
	return ans;
}

int stringtoInt(string str)
{
	int ans=0;
	for(int i=str.size()-1,j=0;i>=0;i--,j++)//从低位到高位依次转化 
		ans+=hextoDec(str[i])*sixteenPower(j);
	return ans;
}

void print(int blknum)
{
	if(blknum>=disklenth*(n-1))//检验块号是否超过阵列的最大容量 
	{
		cout<<"-"<<endl;
		return;
	}
	Block bl=getPosition(blknum);
	for(int j=0;j<l;j++)//检验该块是否存在于已知磁盘上 
	{
		if(disk[j].disknum==bl.disknum)
		{
			string s=disk[j].content.substr(bl.posi*8,8);
			cout<<s<<endl;
			return;
		}
	}
	if(n-1>l)//若不能推导出输出"-" 
	{
		cout<<"-"<<endl;
		return;
	}
	int res=0,b=0;
	string str;
	for(int i=0;i<l;i++)//可以推导出 
	{
		str=disk[i].content.substr(bl.posi*8,8);
		if(b==0)
		{
			b++;
			res=stringtoInt(str);
			continue;
		}
		res=res^stringtoInt(str);
	}
	cout<<hex<<uppercase<<res<<endl;//以16进制大写字母的形式输出
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值