a difficult problem FWT 模板

来源:互联网 发布:50而知天命什么意思 编辑:程序博客网 时间:2024/06/10 09:33


题意:

一个长度为N的序列A,M次询问.

每次询问,满足a \leq A[i] \otimes A[j] \leq baA[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);}}}