http://www.elijahqi.win/archives/3653
https://www.luogu.org/problemnew/show/P4424
观察发现&1 |0没有意义
如果一个最后的答案是1 那么最后一个1 前面出现或 一定排在最后一个&0的n前面 反过来同理
考虑根据添加的运算符构造0,1序列 设1& 0| 那么
把每一个运算符写成0 1 序列之后从右到左分别看做 从高到低的位置 考虑一个位置如果需要出现1 那么 运算符序列和 数字序列 同时是1 或者同时是0 都是可以的 只有出现 运算符为1 原序列为0 这样是不合法的 那么考虑 只要比原序列字典序小的均可
那么 分别针对每个位置形成的01串进行排序 基数排序即可 然后 找到1位置字典序最小的 找到0位置字典序最大的 先判定是否大于0位置的那个 如果大于则有解
解的个数就是他们之间的一个左闭右开的区间
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
const int N=5500;
int n,m,q,bin[N],sa[N],tmp[N],ans[N],cnt[2];
char s[N];
inline void inc(int &x,int v){x=x+v>=mod?x+v-mod:x+v;}
inline int dec(int x,int v){return x-v<0?x-v+mod:x-v;}
int main(){
freopen("bzoj5285.in","r",stdin);
scanf("%d%d%d",&n,&m,&q);bin[0]=1;
for (int i=1;i<=n;++i) bin[i]=bin[i-1]*2%mod;
for (int i=1;i<=m;++i) sa[i]=i;
for (int i=0;i<n;++i){
scanf("%s",s+1);cnt[0]=cnt[1]=0;
for (int j=1;j<=m;++j){
if(s[j]=='0') ++cnt[0];
else ++cnt[1],inc(ans[j],bin[i]);
}cnt[1]+=cnt[0];
for (int j=m;j;--j) tmp[cnt[s[sa[j]]-'0']--]=sa[j];swap(sa,tmp);
}
for (int owo=1;owo<=q;++owo){
scanf("%s",s+1);int l=0,r=m+1;
for (int i=1;i<=m;++i) if (s[sa[i]]-'0') {r=i;break;}
for (int i=m;i;--i) if (s[sa[i]]-'0'==0) {l=i;break;}
if(l>=r) {puts("0");continue;}
printf("%d\n",dec(r==m+1?bin[n]:ans[sa[r]],ans[sa[l]]));
}
return 0;
}