这题真的挺奇妙的
从总体看,纵向分析,先算p1^p2^p3^......pn;
那么还剩下一些取余后在进行异或运算的,它们之间又有什么规律呢?
首先我们把它们写成矩阵的形式
1%1 1%2 1%3 1%4 1%5 .....1%n
2%1 2%2 2%3 2%4 2%5 .....2%n
3%1 3%2 3%3 3%4 3%5 .....3%n
.
.
n%1 n%2 n%3 n%4 n%5 .....n%n
在进入下一步之前,我们要明白这个:当i<j时,i % j = i;
因此这个矩阵可以转化为
1%1 1 1 1...1 (n-1)个1
2%1 2%2 2 2...2 (n-2)个2
3%1 3%2 3%3 3...3 (n-3)个3
.
.
n%1 n%2 n%3 .....n%n
不难发现沿着对角线,一次变为1,2,3,4...
注意一点 偶数个相同的数异或后结果是0,奇数个相同的数异或后结果是1,此时先不要急着算横排的,先看一下竖排的
0 1 1 1 1 1...1
0 0 2 2 2 2...2
0 1 0 3 3 3...3
0 0 1 0 4 4...4
.
.
0............
第一列全是0
第二列是1 0 1 0...
第三列是1 2 0 1 2 0...
第四列是1 2 3 0 1 2 3 0...
如果用a[ i ]表示每一列一个循环内的数字异或的值,那么a[ i ] = a[ i-1 ] ^ i
得到每一列的循环个数以及剩余个数
判断循环个数的奇偶,偶数个相同的数异或后结果是0,奇数个相同的数异或后结果是1,再和剩下的几个数异或
也可以参考点击打开链接(我就是看这里的)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int XOR[1100000];
int main()
{
int ans=0,n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int p;
scanf("%d",&p);
ans^=p;
}
for(int i=1;i<=n-1;i++)//i表示的是列
{
XOR[i]=XOR[i-1]^i;
int len=i+1;//每一列的循环个数都是i+1
int res=n%(len*2);
if(res>=len)//如果 res>=len,那么就有奇数次的循环
{
ans^=XOR[i];
res-=len;
}
ans^=XOR[res];
}
printf("%d\n",ans);
return 0;
}