题意:n个数a[i],两个集合s,t,s中下标最大的小于t中下标最小的(s的元素都在t元素的左边),问s中元素的异或和等于t中元素的and和的方法数,n,a[i]<=1024.
a[i]<=1024 枚举相等的结果x,DP处理出前缀i中异或和为x,后缀i+1中and和为x的方法数
这样计算明显有重复,因为1-p q-n 这两个方案可以在 前缀i,i+1中对应的方案出现(q>>i p<<i)
d[i][x] 集合s最后一个数为i时异或和为x的方法数,同时处理出前缀i异或和为y的个数来转移状态.
a[i]<=1024 枚举相等的结果x,DP处理出前缀i中异或和为x,后缀i+1中and和为x的方法数
这样计算明显有重复,因为1-p q-n 这两个方案可以在 前缀i,i+1中对应的方案出现(q>>i p<<i)
d[i][x] 集合s最后一个数为i时异或和为x的方法数,同时处理出前缀i异或和为y的个数来转移状态.
则集合t可以以i+1,..n开头,即后缀i+1中选and和为x的方法数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1<<11;
ll n,a[N];
ll f[N][N],g[N][N],d[N][N];
int main()
{
int T;
cin>>T;
while(T--)
{
memset(f,0,sizeof(f));
memset(d,0,sizeof(d));
memset(g,0,sizeof(g));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
f[i][a[i]]=1;
d[i][a[i]]=1;
for(int x=0;x<1024;x++)
{
int now=x^a[i];
f[i][now]=(f[i][now]+f[i-1][x])%mod;
f[i][x]=(f[i][x]+f[i-1][x])%mod;
d[i][now]=(f[i-1][x]+d[i][now])%mod;
}
}
for(int i=n;i>1;i--)
{
g[i][a[i]]=1;
for(int x=0;x<1024;x++)
{
int now=x&a[i];
g[i][now]=(g[i][now]+g[i+1][x])%mod;
g[i][x]=(g[i][x]+g[i+1][x])%mod;
}
}
ll ans=0;
for(int x=0;x<1024;x++)
for(int i=1;i<n;i++)
ans=(ans+d[i][x]*g[i+1][x])%mod;
printf("%lld\n",ans);
}
return 0;
}