[bzoj5285][Hnoi2018]寻宝游戏【复杂度分析】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=5285
【题解】
  考虑最后一个影响一个二进制位的数。
  如果出现“&0”,那么之前所有的操作都不能影响它。同理“|1”也是。
  另外两种状态“&1”,“|0”不会影响前面的状态。
  所以从后往前枚举每一位的运算符。如果是“&”所有为0的位置不用再做下去,是“|”所有为1的位置不用做下去。所以一次询问的复杂度是O(NM)的。
  总复杂度:O(NMQ)

# 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;
}
posted @ 2018-04-17 18:41  Vanisher  阅读(88)  评论(0编辑  收藏  举报