10678 神奇的异或
时间限制:1000MS 内存限制:65535K
题型: 编程题 语言: 无限制
Description
在现在这个信息时代,数据是很重要的东西哦~
很多时候,一条关键的数据(情报、信息)是可以价值千金的。
所以,现代也出现了很多数据校验技术来确保数据的正确性。 以下是一种校验算法:
K字节称为一个校验段,校验段的的K个字节的异或结果等于0时,校验段合法。
输入格式
有若干组输入。以EOF为结束。
每组输入第一行是数据长度n,和查询次数qn,以空格隔开。
接下来一行工n*2个字符,是十六进制(大写)表示的n个字节的数据。
然后有qn行输入,每行对应一个查询。
每行查询有pos和k,表示查询从pos位置开始的k个字节的数据能否通过校验。
2<=n<=50000,1<=qn<=20000, 1<=k<=n, 0<=pos<=n-k
输出格式
对于每组数据,输出一行,输出通过检验的次数。
输入样例
10 6
F132274D3CFB0A95009F
1 7
2 7
1 8
1 8
0 9
0 7
输出样例
3
来源
by 200930740513
作者
admin
解题思路
之所以神奇,是因为这题要用到异或再异或之后回到本身这个神奇的性质,题目每一个qn基本都是检验随机一段的合法性,数据量大如果一个一个去异或肯定会超时,采取的办法是记录每一个字节所在位置存储此字节跟前面所有字节异或后的结果(其实只要异或前面字节位置存储的结果),这点在输入字节的时候就需要进行计算。有n个字节就用数组存储n个异或结果,最后一个位置存储的就是全部字节异或的结果。现在如果要求pos位置后面k个字节异或的结果进行检测,那么根据之前存储的总的异或后得结果,用存储的数组下标【k+pos-1】跟【pos-1】下标再一次进行异或就能得到结果,从而判断是否为零
#include<iostream>
#include<cstring>
#include<cstdio>
#define SIZE 16
#define MAXN 50000*2+10
using namespace std; int hexor[SIZE][SIZE];
int store[MAXN];
int n, qn; void init()
{
for(int i=; i<SIZE; ++i)
for(int j=i; j<SIZE; ++j)
hexor[i][j] = hexor[j][i]= i^j;
} int main()
{
char first, second;
int str, stp;
init();
while(scanf("%d%d", &n, &qn) != EOF)
{
getchar();
for(int i=; i<n; ++i)
{
scanf("%c%c", &first, &second);
str = first >= '' && first <= '' ? (first - '') : (first - 'A' + );
stp = second >= '' && second <= '' ? (second - '') : (second - 'A' + );
if(!i) store[i] = str*+stp;
else store[i] = hexor[store[i-]/][str]* + hexor[store[i-]%][stp];
}
int sum = , pos, k, temp;
for(int t=; t<=qn; ++t)
{
scanf("%d%d", &pos, &k);
if(!pos && !store[k+pos-]) sum++;
//这里不能这样写: store[k+pos-1]^store[pos-1] == 0
else if((temp = store[k+pos-]^store[pos-]) == ) sum++;
}
printf("%d\n", sum);
}
return ;
}