题目链接
https://nanti.jisuanke.com/t/38230
题意
给你一个整数n,然后给n个整数,编号1到n。
定义f(L,R)函数为区间 L到R的异或和。
定义g(L,R)函数为 所有f(i,j)的异或和,其中L<=i<=j<=R;
定义w(L,R)函数为 所有g(i,j)的异或和,其中L<=i<=j<=R;
q次查询,每次输入区间 i,j,求w(i,j).
样例
输入
1
5
1 2 3 4 5
5
1 3
1 5
1 4
4 5
3 5
输出
2
4
0
1
4
先打个表找规律
打表程序如下:
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=30;
int a[maxn];
int f[maxn][maxn];
int g[maxn][maxn];
int w[maxn][maxn];
int n=30;
void get(int x){
for(int i=0;i>i&1) cout<
打出来的表是w(1,R)的表。
解释一下这个表,比如R是25 ,结果就是a[1],a[5],a[9],a[13],a[17],a[21],a[25]这些数据的异或和。
根据L到R的区间长度可以分为4种情况。
区间长度x=R-L+1
如果x%4==0输出0
如果x%4==1 结果是 a[L] ,a[L+4],a[L+8]....a[R]的异或和
如果x%4==3, 先将L加1,R减1, 然后结果是 a[L] ,a[L+4],a[L+8]....a[R]的异或和
如果x%4==2 ,结果是x==1和x==3这两种情况的结果异或一下。
所以我们处理一下前缀,就可以每次查询以O(1)的复杂度计算出来。
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int a[maxn];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=5;i<=n;i++) a[i]^=a[i-4];
int q;
scanf("%d",&q);
while(q--){
int i,j;
scanf("%d%d",&i,&j);
int x=j-i+1;
if(x%4==0){
printf("0\n");
}else if(x%4==1){
int ans;
if(i>=4) ans=a[j]^a[i-4];
else ans=a[j];
printf("%d\n",ans);
}else if(x%4==3){
i++;j--;
int ans;
if(i>=4) ans=a[j]^a[i-4];
else ans=a[j];
printf("%d\n",ans);
}else{
int ans;
if(i>=4) ans=a[j]^a[i-4];
else ans=a[j];
i++,j--;
if(i>=4) ans=ans^a[j]^a[i-4];
else ans=ans^a[j];
printf("%d\n",ans);
}
}
}
return 0;
}