题意:给你个有序串,你必须在每2个串中间加入或者,多次询问有多少种方法能得到某一个的串
思路妙♂妙的题啊
分析一下和的性质
>不变
>必为1
>必为0
>不变
考虑对于一个询问串和所有串的某一位
如果某一位为
那么这一位最后必定有一个位置为的地方运算符为
而且这个之后必定没有,即是的地方为,是的地方为
如果某一位为
那么这一位最后必定有一个位置为的地方运算符为
而且这个之后必定没有,即是的地方为,是的地方为
有没有发现什么?
并没有
如果我们把看做,看做
那是不是在比较字典序了
如果最后一位为,那也就是说第一个,即运算符字典序他大的方案
最后一位为同理,即运算符字典序比他小的方案
那对于一位来说,字典序于他的所有方案都合法
那一个串的答案,就是所有合法方案的交集
也就是最低为的位置的答案和最高的一位为的答案的差
把所有串的同一位看做一个串排个序就可以愉快的解决了
#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("");
}
}
}