题意:
一个长度为N的序列A,M次询问.
每次询问,满足a \leq A[i] \otimes A[j] \leq ba≤A[i]⊗A[j]≤b的<A[i],A[j]>有多少对.
注: <A[i],A[j]> 中 i < ji<j.
\otimes⊗代表运算符xorxor,andand,oror.
思路:
一眼,fwt模板题.但是有几个trick.再求FWT时会把自己的加进去,同时对于同一组<a,b><b,a>再本题应该算一次(内部有序即可),但是我们求出来的是两次,所以要注意去掉他们.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = (1 <<20);
LL a[maxn+20],b[maxn+20];
LL sum[maxn+20];
int num[maxn+20];
char op[5];
void FWT_XOR(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j] = x+y,a[i+j+d] = x-y;
}
}
void UFWT_XOR(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
}
}
void solve_XOR(LL a[],LL b[],int n)
{
FWT_XOR(a,n);
FWT_XOR(b,n);
for(int i=0;i<n;i++) a[i]=a[i]*b[i];
UFWT_XOR(a,n);
}
void FWT_OR(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j+d]=x+y;
}
}
void UFWT_OR(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j+d]=y-x;
}
}
void solve_OR(LL a[],LL b[],int n)
{
FWT_OR(a,n);
FWT_OR(b,n);
for(int i=0;i<n;i++) a[i]=a[i]*b[i];
UFWT_OR(a,n);
}
void FWT_AND(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m = d << 1,i = 0;i < n;i += m)
for(int j=0;j<d;j++)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j]=x+y;
}
}
void UFWT_AND(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d << 1,i = 0;i < n;i += m)
for(int j=0;j<d;j++)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j]=x-y;
}
}
void solve_AND(LL a[],LL b[],int n)
{
FWT_AND(a,n);
FWT_AND(b,n);
for(int i=0;i < n;i++) a[i]=a[i]*b[i];
UFWT_AND(a,n);
}
int main()
{
int _;
cin>>_;
while(_--)
{
int n,q;
for(int i = 0;i < maxn;++i)
a[i] = 0,b[i] = 0,num[i] = 0,sum[i] = 0;
scanf("%d %d %s",&n,&q,op);
for(int i = 1;i <= n;++i)
{
int x;
scanf("%d",&x);
++a[x];
++b[x];
if(op[0] == '^') ++num[x ^ x];
if(op[0] == '&') ++num[x & x];
if(op[0] == '|') ++num[x | x];
}
if(op[0] == '^') solve_XOR(a,b,maxn);//位运算值域的上限要求必须为2的次幂
if(op[0] == '&') solve_AND(a,b,maxn);
if(op[0] == '|') solve_OR(a,b,maxn);
//cout<<a[0] <<endl;
for(int i = 0;i < maxn;++i)
a[i] -= num[i],a[i]/=2;
sum[0] = a[0];
for(int i = 1; i < maxn;++i)
sum[i] = sum[i-1] + a[i];
while(q--)
{
int l,r;
scanf("%d %d",&l,&r);
LL ans = 0;
ans = sum[r] - sum[l] + a[l];
//ans -= (s[r] - s[l] + num[l]);
printf("%lld\n",ans);
}
}
}