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=1111111011∧00111=00011,11011∨00111=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 30n≤20,m≤30,q=1q = 1q=1
对于另外 20%20\%20% 的数据,n≤1000n \le 1000n≤1000,m≤16m \le 16m≤16
对于另外 40%40\%40% 的数据,n≤500n \le 500n≤500,m≤1000m \le 1000m≤1000
对于 100%100\%100% 的数据,1≤n≤10001 \le n \le 10001≤n≤1000,1≤m≤50001 \le m \le 50001≤m≤5000,1≤q≤10001 \le q \le 10001≤q≤1000
#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; }
#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; }