对于一个表达式,我们可以记录
4
4
4个变量的每种不同取值(共
2
4
=
16
2^4=16
24=16种)所对应的不同结果,于是可以把一个表达式看成一个长度为
16
16
16的二进制串,这样的串总共有
2
16
2^{16}
216种。
回到原问题,我们把表达式树建出来,对每个节点
x
x
x维护子树中的表达式不同填法所对应的每种二进制串
s
t
st
st的个数
F
[
x
]
[
s
t
]
F[x][st]
F[x][st]。那么考虑
x
x
x处填的符号为
a
n
d
and
and或
o
r
or
or,分别对应把左右儿子对应的二进制串
a
n
d
and
and和
o
r
or
or起来,于是实质上是做了一个
a
n
d
and
and卷积和
o
r
or
or卷积,容易用高维前/后缀和实现。这样也可以方便的统计答案。
时间复杂度
O
(
∣
s
∣
⋅
2
16
⋅
16
)
\mathcal O(|s|\cdot 2^{16} \cdot 16)
O(∣s∣⋅216⋅16)。
#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
typedef long long ll;
inline void add(int &x,int y) {
((x+=y)>=MOD)?x-=MOD:0;
}
inline void sub(int &x,int y) {
((x-=y)<0)?x+=MOD:0;
}
void fwt1(int *p,int len) {
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j++)
if (j&i) add(p[j],p[j^i]);
}
void fwt2(int *p,int len) {
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j++)
if (j&i) add(p[j^i],p[j]);
}
void ifwt1(int *p,int len) {
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j++)
if (j&i) sub(p[j],p[j^i]);
}
void ifwt2(int *p,int len) {
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j++)
if (j&i) sub(p[j^i],p[j]);
}
char str[505];
int f[505][1<<16],tot;
int p[1<<16],q[1<<16];
int solve(int l,int r) {
int o=++tot;
if (l==r) {
if (str[l]=='A'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if ((i>>0)&1) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='B'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if ((i>>1)&1) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='C'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if ((i>>2)&1) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='D'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if ((i>>3)&1) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='a'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if (!((i>>0)&1)) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='b'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if (!((i>>1)&1)) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='c'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if (!((i>>2)&1)) st|=(1<<i);
f[o][st]=1;
}
if (str[l]=='d'||str[l]=='?') {
int st=0;
for(int i=0;i<16;i++)
if (!((i>>3)&1)) st|=(1<<i);
f[o][st]=1;
}
return o;
}
int ls,rs,mid;
if (str[l]=='(') {
int d=0;
for(int i=l;i<=r;i++)
if (str[i]=='(') d++;
else if (str[i]==')') {
d--;
if (!d) {
ls=solve(l+1,i-1);
mid=i+1;
break;
}
}
}
else {
ls=solve(l,l);
mid=l+1;
}
if (str[r]==')') {
int d=0;
for(int i=r;i>=l;i--)
if (str[i]==')') d++;
else if (str[i]=='(') {
d--;
if (!d) {
rs=solve(i+1,r-1);
break;
}
}
}
else rs=solve(r,r);
if (str[mid]!='&') {
memcpy(p,f[ls],sizeof(p));
memcpy(q,f[rs],sizeof(q));
fwt1(p,1<<16);
fwt1(q,1<<16);
for(int i=0;i<(1<<16);i++) p[i]=(ll)p[i]*q[i]%MOD;
ifwt1(p,1<<16);
for(int i=0;i<(1<<16);i++) add(f[o][i],p[i]);
}
if (str[mid]!='|') {
memcpy(p,f[ls],sizeof(p));
memcpy(q,f[rs],sizeof(q));
fwt2(p,1<<16);
fwt2(q,1<<16);
for(int i=0;i<(1<<16);i++) p[i]=(ll)p[i]*q[i]%MOD;
ifwt2(p,1<<16);
for(int i=0;i<(1<<16);i++) add(f[o][i],p[i]);
}
return o;
}
int main() {
scanf("%s",str+1);
int n=strlen(str+1);
solve(1,n);
int m;
scanf("%d",&m);
int st=0,bel=0;
for(int i=1;i<=m;i++) {
int t=0;
for(int j=0;j<4;j++) {
int x;
scanf("%d",&x);
if (x) t|=(1<<j);
}
int x;
scanf("%d",&x);
if (x) st|=(1<<t);
bel|=(1<<t);
}
int ans=0;
for(int i=0;i<(1<<16);i++)
if ((i&bel)==st) add(ans,f[1][i]);
printf("%d\n",ans);
return 0;
}