题意:给你nnn个有序010101串,你必须在每2个串中间加入&\&&或者∣|∣,多次询问有多少种方法能得到某一个的串
思路妙♂妙的题啊
分析一下&\&&和∣|∣的性质
∣ 0−|\ 0-∣ 0−>不变
∣ 1−|\ 1-∣ 1−>必为1
&0−\&0-&0−>必为0
&1−\&1-&1−>不变
考虑对于一个询问串qqq和所有串的某一位
如果qqq某一位为000
那么这一位最后必定有一个位置为000的地方运算符为&\&&
而且这个&\&&之后必定没有∣1|1∣1,即是000的地方为∣|∣,是111的地方为&\&&
如果qqq某一位为111
那么这一位最后必定有一个位置为111的地方运算符为∣|∣
而且这个∣|∣之后必定没有&0\& 0&0,即是000的地方为∣|∣,是111的地方为&\&&
有没有发现什么?并没有
如果我们把∣|∣看做‘0’‘0’‘0’,111看做‘1’‘1’‘1’
那是不是在比较字典序了
如果最后一位为000,那也就是说第一个&0\& 0&0,即运算符字典序他大的方案
最后一位为111同理,即运算符字典序比他小的方案
那对于qqq一位0/10/10/1来说,字典序大/小大/小大/小于他的所有方案都合法
那一个串的答案,就是所有合法方案的交集
也就是qqq最低为111的位置的答案和最高的一位为000的答案的差
把所有串的同一位看做一个串排个序就可以愉快的解决了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
const ll mod=1e9+7;
const int M=5005;
int n,m,q;
ll sum[M];
char s[M],r[M];
struct line{
int id;
char a[M];
}p[M];
inline bool comp(const line &a,const line &b){
for(int i=1;i<=n;i++){
int f1=a.a[i]-'0',f2=b.a[i]-'0';
if(f1==f2)continue;
return f1<f2;
}
}
inline ll calc(int x){
ll res=0;
for(int i=1;i<=n;i++){
res=res*2%mod;
if(p[x].a[i]=='1')res++;
}
return res;
}
inline ll ksm(ll a,int b,ll res=1){
for(;b;b>>=1,a=a*a%mod){
if(b&1)res=res*a%mod;
}
return res;
}
signed main(){
n=read(),m=read(),q=read();
ll mx=ksm(2,n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
p[j].a[n-i+1]=s[j];
}
}
for(int i=1;i<=m;i++)p[i].id=i;
sort(p+1,p+m+1,comp);
for(int i=1;i<=m;i++)
sum[i]=calc(i);
for(int i=1;i<=q;i++){
scanf("%s",s+1);
int pos1=0,pos2=0;
for(int j=1;j<=m;j++){
if(s[p[j].id]-'0'){
pos1=j;break;
}
}
for(int j=m;j;j--){
if(!(s[p[j].id]-'0')){
pos2=j;break;
}
}
if(pos1&&pos2&&pos2>pos1)puts("0");
else{
if(pos1)cout<<(sum[pos1]-sum[pos2]+mod)%mod;
else cout<<(mx-sum[pos2]+mod)%mod;
puts("");
}
}
}