loj #2494. 「AHOI / HNOI2018」寻宝游戏

#2494. 「AHOI / HNOI2018」寻宝游戏

 

题目描述

某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会。

作为新生的你对这个活动非常感兴趣。你每天都要从西向东经过教学楼一条很长的走廊,这条走廊是如此的长,以至于它被人戏称为 infinite corridor。一次,你经过这条走廊的时,注意到在走廊的墙壁上隐藏着 nnn 个等长的二进制的数字,长度均为 mmm。你从西向东将这些数字记录了下来,形成一个含有 nnn 个数的二进制数组 a1,a2,...,ana_1, a_2, ..., a_na1​​,a2​​,...,an​​。很快,在最新的一期 Voo Doo 杂志上,你发现了 qqq 个长度也为 mmm 的二进制串 r1,r2,...,rqr_1, r_2, ..., r_qr1​​,r2​​,...,rq​​。聪明的你很快发现了这些数字的含义。保持数组 a1,a2,...,ana_1, a_2, ..., a_na1​​,a2​​,...,an​​ 的元素顺序不变,你可以在它们之间插入 ∧\wedge∧(按位与运算)或者 ∨\vee∨(按位或运算)两种二进制运算符。例如:11011∧00111=00011,11011∨00111=1111111011 \wedge 00111=00011,11011 \vee 00111=111111101100111=00011,1101100111=11111。

你需要插入恰好 nnn 个运算符,相邻两个数之间恰好一个,在第一个数的左边还有一个。如果我们在第一个运算符的左边补入一个 000,这就形成了一个运算式,我们可以计算它的值。与往常一样,运算顺序是从左往右。有趣的是,出题人已经告诉你这个值的可能的集合——Voo Doo 杂志里的那一些二进制数 r1,r2,...,rqr_1, r_2, ..., r_qr1​​,r2​​,...,rq​​,而解谜的方法,就是对 r1,r2,...,rqr_1, r_2, ..., r_qr1​​,r2​​,...,rq​​ 中的每一个值 rir_iri​​,分别计算出有多少种方法填入这 nnn 个运算符,使得这个运算式的值是 rir_iri​​ 。然而,infinite corridor 真的很长,这意味着数据范围可能非常大。因此,答案也可能非常大,但是你发现由于谜题的特殊性,你只需要求答案模 100000000710000000071000000007 (109+710^9 + 7109​​+7,一个质数)的值。

输入格式

第一行三个数 n,m,qn, m, qn,m,q,含义如题所述。

接下来 nnn 行,其中第 iii 行有一个长度为 mmm 的二进制串,左边是最高位,表示 aia_iai​​ 。

接下来 qqq 行,其中第 iii 行有一个长度为 mmm 的二进制串,左边是最高位,表示 rir_iri​​ 。

输出格式

输出 qqq 行,每行一个数,其中第 iii 行表示对应于 rir_iri​​ 的答案。

样例

样例输入 1

5 5 1
01110
11011
10000
01010
00100
00100

样例输出 1

6

样例输入 2

10 10 3
0100011011
0110100101
1100010100
0111000110
1100011110
0001110100
0001101110
0110100001
1110001010
0010011101
0110011111
1101001010
0010001001

样例输出 2

69
0
5

数据范围与提示

对于 10%10\%10% 的数据,n≤20,m≤30n \le 20, m \le 30n20,m30,q=1q = 1q=1

对于另外 20%20\%20% 的数据,n≤1000n \le 1000n1000,m≤16m \le 16m16

对于另外 40%40\%40% 的数据,n≤500n \le 500n500,m≤1000m \le 1000m1000

对于 100%100\%100% 的数据,1≤n≤10001 \le n \le 10001n1000,1≤m≤50001 \le m \le 50001m5000,1≤q≤10001 \le q \le 10001q1000

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 50
using namespace std;
int n,m,q;
bool a[maxn][maxn],b[maxn],c[maxn];
bool check(int sta){
    memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(sta&(1<<i-1)) b[j]=(b[j]&a[i][j]);
            else b[j]=(b[j]|a[i][j]);
        }
    for(int i=1;i<=m;i++)if(b[i]!=c[i])return 0;
    return 1;
}
int main(){
    char s[maxn];
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
            a[i][j]=s[j]=='0'?0:1;
    }
    scanf("%s",s+1);
    for(int i=1;i<=m;i++)c[i]=s[i]=='0'?0:1;
    int ans=0;
    for(int sta=0;sta<(1<<n);sta++)
        if(check(sta))ans++;
    printf("%d",ans);
    return 0;
}
10分 暴力
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 5010
#define mod 1000000007
using namespace std;
int n,m,q,rk[maxn],sum[maxn],tmp[maxn],pows[maxn];
char s[maxn];
int main(){
    freopen("Cola.txt","r",stdin);
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++)rk[i]=i;
    pows[0]=1;
    for(int i=1;i<=n;i++)
        pows[i]=1LL*pows[i-1]*2%mod;
    for(int i=1;i<=n;i++){
        int cnt[]={0,0};
        scanf("%s",s+1);
        for(int j=1;j<=m;j++){
            sum[j]=(sum[j]+1LL*(s[j]-'0')*pows[i-1])%mod;
            cnt[s[j]-'0']++;
        }
        cnt[1]+=cnt[0];
        for(int j=m;j>=1;j--)
            tmp[cnt[s[rk[j]]-'0']--]=rk[j];
        swap(rk,tmp);
    }
    reverse(rk+1,rk+m+1);
    for(int i=1;i<=q;i++){
        scanf("%s",s+1);
        int lst1=0,fst0=m+1;
        for(int j=m;j>=1&&lst1==0;j--)
            if(s[rk[j]]-'0')lst1=j;
        for(int j=1;j<=m&&fst0==m+1;j++)
            if(!(s[rk[j]]-'0'))fst0=j;
        if(lst1>fst0){puts("0");continue;}
        int c0=lst1>=1?sum[rk[lst1]]:pows[n];
        int c1=fst0<=m?sum[rk[fst0]]:0;
        printf("%d\n",(c0-c1+mod)%mod);
    }
    return 0;
}
100分

 

posted @ 2018-04-24 12:31  Echo宝贝儿  阅读(452)  评论(0编辑  收藏  举报