[bzoj5285][Hnoi2018]寻宝游戏【复杂度分析】
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=5285
【题解】
考虑最后一个影响一个二进制位的数。
如果出现“&0”,那么之前所有的操作都不能影响它。同理“|1”也是。
另外两种状态“&1”,“|0”不会影响前面的状态。
所以从后往前枚举每一位的运算符。如果是“&”所有为0的位置不用再做下去,是“|”所有为1的位置不用做下去。所以一次询问的复杂度是的。
总复杂度:。
# include <bits/stdc++.h>
# define N 1010
# define M 5010
# define P 1000000007
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
int n,m,q,ans;
char s[N][M],t[M];
int use[N][M],mul[N];
int solve(int k, int cnt){
if (cnt==0) return mul[k];
if (k==0){
for (int i=1; i<=cnt; i++)
if (t[use[k][i]]=='1')
return 0;
return 1;
}
int nex=0, flag=true, num=0;
for (int i=1; i<=cnt; i++){ // ^
if (s[k][use[k][i]]=='0'){
if (t[use[k][i]]=='1'){
flag=false; break;
}
}
else use[k-1][++nex]=use[k][i];
}
if (flag) num=num+solve(k-1,nex);
nex=0, flag=true;
for (int i=1; i<=cnt; i++){ // v
if (s[k][use[k][i]]=='1'){
if (t[use[k][i]]=='0'){
flag=false; break;
}
}
else use[k-1][++nex]=use[k][i];
}
if (flag) num=(num+solve(k-1,nex))%P;
return num;
}
int main(){
n=read(), m=read(); q=read();
mul[0]=1;
for (int i=1; i<=n; i++)
mul[i]=mul[i-1]*2%P;
for (int i=1; i<=n; i++)
scanf("\n%s",s[i]+1);
while (q--){
scanf("\n%s",t+1);
for (int i=1; i<=m; i++) use[n][i]=i;
ans=solve(n,m);
printf("%d\n",ans);
}
return 0;
}