CCF-CSP 201903-3-损坏的RAID5 (Python) 满分实现

201903-3-损坏的RAID5

问题

image-20230307003549049

image-20230306225334675

image-20230307003621916

思路

分类:

  1. 指定的块超出阵列总长度,则print('-')
  2. 不超出阵列总长度
    • 包含所请求数据的硬盘已知,则打印所请求的数据
    • 现存的硬盘数足够(l >= n - 1),则通过异或计算获得缺失的数据
    • 阵列不完整,现存的硬盘数不足够(l < n - 1),则print('-')
核心算法在于计算所请求数据的硬盘地址和块偏移

实现

def func(txts):  # 计算八位字符串异或值
    out = 0
    for txt in txts:
        out = out ^ eval('0x' + txt)
    return '%X' % (out,)

n, s, l = eval(input().replace(' ', ',')) # n硬盘的数目,s条带的大小,l现存的硬盘数目
disks = ['' for i in range(n)]
for i in range(l):
    num, txt = input().split(' ')
    disks[int(num)] = txt # disks列表存,i硬盘字符串数据[0,n)

max_num = len(disks[0]) // 8 * (n - 1) # 可访问块的最大序号
m = int(input()) # 查询的次数
for i in range(m):
    num = int(input()) # 访问块的序号[0,max_num)
    # 指定的块超出阵列总长度
    if num >= max_num: 
        print('-')
    # 对于每个查询,计算所请求数据的硬盘地址和块偏移
    else: 
        addr_disk = num // (s * (n - 1)) * s + num % s  # 盘内偏移块数
        addr_c = num // (s * (n - 1))  # 层数
        addr_n = (num // s) % (n - 1)  # 层顺序
        addr_p = n - 1 - addr_c % n  # P区层偏移
        addr_d = addr_p + 1 + addr_n if addr_p + 1 + \
            addr_n < n else addr_n - (n - addr_p - 1)  # 层偏移
      	# 如果包含所请求数据的硬盘已知,则打印所请求的数据
        if disks[addr_d] != '': 
            print(disks[addr_d][addr_disk * 8:(addr_disk + 1) * 8])
        # 如果现存的硬盘数足够(l >= n - 1),则通过异或计算获得缺失的数据
        elif l >= n - 1: 
            txts = []
            for i, txt in enumerate(disks):
                if i != addr_d:
                    txts.append(txt[addr_disk * 8:(addr_disk + 1) * 8])
            print(func(txts))
        # 阵列不完整,现存的硬盘数不足够(l < n - 1)
        else:
            print('-')

image-20230307000918782

1、计算字符串异或值

def func(txts):  # 将输入的字符串中的每位之间进行异或运算
	out = 0
 	for txt in txts:
     out = out ^ eval('0x' + txt)
 	return '%X' % out
  • 使用^运算符将输入的字符串中的每位之间进行异或运算
  • eval()函数被用于将每个输入列表中的字符串解释为十六进制整数值,以便执行异或运算。在每次循环迭代中,字符串 '0x' + txt 被传递给eval()函数,表示将十六进制字符串txt转换为一个十六进制整数值。
  • '%X':格式化符号将整数转换为十六进制

2、n, s, l = eval(input().replace(' ', ',')) # n硬盘的数目,s条带的大小,l现存的硬盘数目

eval() 函数用于将字符串当作 Python 代码执行,并返回执行结果。在这个例子中,replace() 函数返回的字符串被当作一个 Python 表达式执行,其中包含了三个整数值,这三个整数值用逗号 , 分隔。eval() 函数将这个表达式求值,并将其结果赋给三个变量 nsl,这三个变量分别代表硬盘的数目、条带的大小和现存的硬盘数目。

3、

addr_d = addr_p + 1 + addr_n if addr_p + 1 + \
            addr_n < n else addr_n - (n - addr_p - 1)  # 层偏移

例如,假设当前地址 addr_p 为 8,下一个地址 addr_n 为 5,而总长度 n 为 10。则按照上述计算方法,可以得到:

addr_d = addr_p + 1 + addr_n if addr_p + 1 + addr_n < n else addr_n - (n - addr_p - 1)
      = 8 + 1 + 5 if 8 + 1 + 5 < 10 else 5 - (10 - 8 - 1)
      = 14 if 14 < 10 else 5 - 1
      = 4

因此,下一个地址 addr_d 就是 4。

4、enumerate()

在 Python 中,enumerate() 是一个内置函数,它用于在遍历可迭代对象时,同时返回该对象的元素以及该元素在可迭代对象中的索引。

Appendx

Python的位运算符

按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、同或

同或运算可以用按位异或(^)运算符和逻辑非(not)运算符组合实现,具体的实现方式如下:

a = True
b = False
c = not (a ^ b)  # c的值为True,因为a和b的值不同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值