核: 阵列由n+1个磁盘组成,每个磁盘由块(8位字符串)组成,s个块组成一个条带.
我们把每一个磁盘的编号disk看出纵坐标, 条带k看出横坐标.(所有磁盘的第一个条带k值相同),本题实质就是根据块号x查找(k,disk)的过程
首先我们求出块x所在的条带号y: y=x/s
然后同一排有n个条带, 那么可以得出: k=y/n
冗余条带的位置从第一排开始为从右往左,同一排的数据带编号紧跟冗余带从左往右, 那么第k排冗余带的位置 rd=n-k%(n+1), 那么第y条数据带的disk=(rd+y%n+1)%(n+1)
最后我们将块号x细化到第disk个磁盘的第start块: start=x%s+k*s, 数据开始的位置_start=start*8
红色标记表示为k值
坑:
1.题目中所指出的“硬盘数据大小 40KiB”指的是原始数据的大小,不是测试集中给出的16进制字符串的大小。
因为硬盘原始数据的长度是其对应16进制表示的字符串长度的1/2(不考虑空格)。如果采用静态存储类型的数组放置字符串,其元素个数不应少于3*40KiB。
2.本题具有大量I/O,容易在I/O消耗大量时间,造成超时。
std::ios::sync_with_stdio(false);
iostream默认是与stdio关联在一起的,以使两者同步,因此消耗了iostream不少性能。C++中的std :: cin和std :: cout为了兼容C,保证在代码中同时出现std :: cin和scanf或std :: cout和printf时输出不发生混乱,所以C++用一个流缓冲区来同步C的标准流。通过std :: ios_base :: sync_with_stdio函数设置为false后可以解除这种同步,让std :: cin和std :: cout不再经过缓冲区,iostream的性能就会提高了很多倍。
因此,当解除同步之后,注意不要与scanf、printf、puts等cstdio库中的输入输出函数混用以免出现问题。
#include#include using namespace std; const string base="0123456789ABCDEF"; const int N=1e3+5; string d[N];int n,s,l,q,max_k; inline int to_int(char c){ if(c>='0'&&c<='9') return c-'0'; return c-'A'+10; } inline void Xor(string &ans,string str){ for(int i=0,x,y;i<8;i++){ x=to_int(ans[i]); y=to_int(str[i]); ans[i]=base[x^y]; } } string get_xor(int disk,int _start){ string ans(8,'0'); for(int i=0;i<=n;i++){ if(i!=disk){ Xor(ans,d[i].substr(_start,8)); } } return ans; } int main(){ ios::sync_with_stdio(false);//使用string必加,or TLE cin>>n>>s>>l;n--;//(n块数据,1块冗余) for(int i=0,id;i ){ cin>>id;cin>>d[id]; // cin>>id>>d[id];//不知道为什么错 max_k=d[id].size()/8/s; } cin>>q; for(int x,y,k,disk,sz,_start;q--;){ cin>>x; y=x/s; k=y/n; disk=(n-k%(n+1)+y%n+1)%(n+1); sz=d[disk].size(); if(k>=max_k) cout<<"-\n"; else if(sz){ _start=8*(x%s+k*s); cout< 8)<<'\n'; } else if(!sz&&l==n){ _start=8*(x%s+k*s); cout< '\n'; } else cout<<"-\n"; } return 0; }
——参考自网络