先考虑把所有数取反,问题变成求使得所有数的或和为全集,且任意一个缺一个数的子集的或和都不为全集的方案数
考虑dp,f[i][j][k]表示在前i个数中选了一些,这些数或和为j,要求k是后n-i个数里选出来的数的或和的子集的方案数
不要问我为什么会有这种鬼畜状态-_-
那么考虑转移,设第i+1个数为x,假设第i+1个数不选,那么f[i+1][j][k]+=f[i][j][k]
如果第i个数选,那么我们先保证x不是前面选的数的子集,即以下转移要求x&j!=x
经WerKeyTom_FTD神犇提醒,观察下面的转移式,我们发现当x&j==x的时候,相当于没做转移,所以不用判这个
那么考虑用所有的方案减去x是后面选的数的子集的方案,即
f[i+1][j|x][k^(k&x)]+=f[i][j][k]//所有的的方案
f[i+1][j|x][(k^(k&x))|(x^(x&j))]-=f[i][j][k]//不合法的方案
那么这样复杂度就是n*4^m的,m为二进制位的个数
观察转移式中k那一维的表达式,初始值为f[0][0][0]=1,那么瞎jb归纳以下可得f[i][j][k]!=0的必要条件是k是j的子集
那么复杂度就降到n*3^m了
#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 1024
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
int N=1023;
int n;
int f[MAXN][MAXN],g[MAXN][MAXN];
int main(){
int i,j,k,x;
scanf("%d",&n);
f[0][0]=1;
for(i=1;i<=n;i++){
scanf("%d",&x);
x^=N;
for(j=0;j<=N;j++){
for(k=j;;k=k-1&j){
g[j][k]=0;
if(!k){
break;
}
}
}
for(j=0;j<=N;j++){
if((x&j)!=x){
for(k=j;;k=k-1&j){
(g[j|x][k&(~x)]+=f[j][k])%=MOD;
(g[j|x][(k&(~x))|(x&(~j))]+=MOD-f[j][k])%=MOD;
if(!k){
break;
}
}
}
}
for(j=0;j<=N;j++){
for(k=j;;k=k-1&j){
(f[j][k]+=g[j][k])%=MOD;
if(!k){
break;
}
}
}
}
printf("%d\n",f[N][0]);
return 0;
}
/*
4
1 2 4 4
*/