题目大意
给定
n
个数
题目分析
又是一道好题。
在范老师@AwD的博客看懂的,大家可以过去膜拜一下。
思路是这样的:令
Sa
为
S
删去
那么答案就是
∑S[(f(S)=0)∧∧a∈S(f(Sa)≠0)]
这个看起来不太好算,我们对后面的部分容斥一下,变成
∑S∑S′⊆S[(f(S)=0)∧∧a∈S′(f(Sa)=0)](−1)|S′|
其实就是
∑S∑S′⊆S[(f(S)=0)∧(∨a∈S′f(Sa)=0)](−1)|S′|
这个怎么计算呢?令 fi,k,j 表示做到了第 i 个位置,
显然必须要满足 k⊆j ,也就是说状态数只有 O(n310) 。
转移的话,假设第 i+1 个数是 d ,那么有三种转移:
∙ S 中选择了 d ,但是
∙ S 以及 S′ 中都选择了 d :
初始状态 f0,210−1,210−1=1 ,目标状态 fn,0,0 。
时间复杂度 O(n310) 。
代码实现
#include <iostream>
#include <cctype>
#include <cstdio>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int P=1000000007;
const int N=1005;
const int S=1024;
int f[2][S][S];
int a[N];
int n;
void update(int &x,int y){x=(x+y)%P;}
int dp()
{
f[0][S-1][S-1]=1;
for (int i=0;i<n;++i)
{
int cur=i&1,nxt=cur^1,x=a[i+1];
for (int j=0;j<S;++j)
{
for (int k=j;k;k=(k-1)&j) f[nxt][k][j]=0;
f[nxt][0][j]=0;
}
for (int j=0;j<S;++j)
{
for (int k=j;k;k=(k-1)&j) update(f[nxt][k][j],f[cur][k][j]),update(f[nxt][k&x][j&x],f[cur][k][j]),update(f[nxt][k&x][k|j&x],P-f[cur][k][j]);
update(f[nxt][0][j],f[cur][0][j]);
}
}
return f[n&1][0][0];
}
int main()
{
freopen("never.in","r",stdin),freopen("never.out","w",stdout);
n=read();
for (int i=1;i<=n;++i) a[i]=read();
printf("%d\n",dp());
fclose(stdin),fclose(stdout);
return 0;
}