ccf 201903-3 损坏的RAID5

Posted zbhfz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ccf 201903-3 损坏的RAID5相关的知识,希望对你有一定的参考价值。

9月份考ccf,暑假打算做一些往年的真题。。。

这个题,一开始真是把我给看晕了

传说中的大模拟,果然不简单QAQ

 

首先读懂题目就是一个大难点,特别是对于我这种题目一长就看不进去的人来说

读懂题目之后,思路就好想了,下面简单说一下我的思路:

  首先定义一个字符数组ss[N][M],然后用ss[i]存入编号为 i 的硬盘后面的字符串,

  在后面处理的时候就可以用sscanf函数直接获取ss[i]中相应位置的十六进制数(输入用"%8x",输出用"%08X")。

  再一个比较烧脑的地方就是根据输入的块的编号b确定该块所在的硬盘和条带编号

    条带编号k=b/s/(n-1);  结合图从左到右读这个式子就能想明白

    所在硬盘编号t=n-1+k*(n-1)+b/s%(n-1)+1; t%=n; 其中n-1是条带编号为0对应的校验盘位置,条带编号+1,校验盘-1(等价于+(n-1)); b/s%(n-1)是块所在硬盘相对校验盘的偏移量。

 

一开始我输入语句是这样写的:

1     for(int i=0;i<l;i++)
2         int x;
3         scanf("%d",&x);
4         scanf("%s",ss[x]);
5     

然后就是各种超时,哪怕我想方设法优化代码,怎么搞也只有70分

我就纳闷了,这时间复杂度我满打满算也不过1e7啊,咋就超时了呢?

 

百思不得其解,于是毅然百度。。。

然后发现很多几个题解都是用的很c++风格的代码,算法复杂度和我没什么区别,而且用的cin,居然还比scanf快???

于是乎,我发现了一条神奇的代码

1   ios::sync_with_stdio(false);

据说它可以关闭c++的流同步,防止cin超时

于是乎,我试着把所有的标准输入换成了cin,加上那句我看不懂的玩意儿,居然还真过了!!!

技术图片
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 typedef long long ll;
 6 const int M=10240*8+1;
 7 const int N=1000;
 8 char ss[N][M];
 9 int main()
10 
11     //freopen("in.txt","r",stdin);
12     ios::sync_with_stdio(false);
13     int n,s,l;
14     cin>>n>>s>>l;//scanf("%d%d%d",&n,&s,&l);
15     for(int i=0;i<l;i++)
16         int x;
17         cin>>x;//scanf("%d",&x);
18         cin>>ss[x];//scanf("%s",ss[x]);
19     
20     int m;
21     cin>>m;//scanf("%d",&m);
22     while(m--)
23         ll b;
24         cin>>b;//scanf("%lld",&b);
25         ll t=n-1+b/s/(n-1)*(n-1)+b/s%(n-1)+1,k=(b/s/(n-1)*s+b%s)*8;t%=n;
26         if(k>=M||ss[t][0]==0&&l<n-1||ss[0][k]==0&&ss[1][k]==0&&ss[t][k]==0)
27             printf("-\n");
28             continue;
29         
30         if(ss[t][0]==0)
31             ll ans=0;
32             for(int i=0;i<n;i++)
33                 if(i==t)continue;
34                 ll x;
35                 sscanf(ss[i]+k,"%8x",&x);
36                 ans^=x;
37             
38             printf("%08X\n",ans);
39         
40         else
41             ll ans;
42             sscanf(ss[t]+k,"%8x",&ans);
43             printf("%08X\n",ans);
44         
45     
46     return 0;
47 
View Code

 

但是scanf超时超在哪呢???

直到之后又看到一篇博客,我才知道字符串输入用scanf会超时,因为最后三组数据40kb的数据长度,意味着一个字符串最多有80kb个字符要输入,而一次最多有1000个字符串待输入,输入数据量贼大

于是改用专门的字符串输入函数gets或fgets就没问题了(不过据说gets大势已去,建议尽量用fgets)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 typedef long long ll;
 6 const int M=10240*8+1;
 7 const int N=1000;
 8 char ss[N][M];
 9 int main()
10 
11     //freopen("in.txt","r",stdin);
12     int n,s,l;
13     scanf("%d%d%d",&n,&s,&l);
14     for(int i=0;i<l;i++)
15         int x;
16         scanf("%d%*c",&x);
17         fgets(ss[x],M,stdin);//gets(ss[x]);
18     
19     int m;
20     scanf("%d",&m);
21     while(m--)
22         ll b;
23         scanf("%lld",&b);
24         ll t=n-1+b/s/(n-1)*(n-1)+b/s%(n-1)+1,k=(b/s/(n-1)*s+b%s)*8;t%=n;
25         if(k>=M||ss[t][0]==0&&l<n-1||ss[0][k]==0&&ss[1][k]==0&&ss[t][k]==0)
26             printf("-\n");
27             continue;
28         
29         if(ss[t][0]==0)
30             ll ans=0;
31             for(int i=0;i<n;i++)
32                 if(i==t)continue;
33                 ll x;
34                 sscanf(ss[i]+k,"%8x",&x);
35                 ans^=x;
36             
37             printf("%08X\n",ans);
38         
39         else
40             ll ans;
41             sscanf(ss[t]+k,"%8x",&ans);
42             printf("%08X\n",ans);
43         
44     
45     return 0;
46 

 

以上是关于ccf 201903-3 损坏的RAID5的主要内容,如果未能解决你的问题,请参考以下文章

csp 201903-3损坏的RAID5

模拟RAID5损坏

配置RAID5磁盘阵列并尝试磁盘损坏自动替换功能

EMC FC AX-4存储崩溃,raid5硬盘损坏的数据恢复过程

HIS医院信息系统主服务器RAID5崩溃 硬盘损坏 SQL数据库损坏修复 SQL SERVER数据库修复 备份文件无法还原数据恢复

服务器数据恢复raid5崩溃导致lvm信息和VXFS文件系统损坏的数据恢复案例