不是很像 ( ext{CN}) 省选的题,个人感觉更像是 ( ext{JOI}) 那类风格的题(?
对于这种位运算题,一上来肯定先想到拆位并找寻位运算的规律。
-
对于 (vee) 而言,任何一位的二进制数 (vee 0) 都为其自身,(vee 1) 都为 (1)。
-
对于 (wedge) 而言,任何一位的二进制数 (wedge 1) 都为其自身,(wedge 0) 都为 (0)。
这提醒我们,对于每一位而言,只有 (wedge 0,vee 1) 能够改变这一位上的状态。
考虑 (m=1) 的情况。若最终运算结果为 (1),最后一个 (vee 1) 必然在 (wedge 0) 之后(也可以不存在 (wedge 0),但一定有 (vee 1));若最终运算结果为 (0),最后一个 (vee 1) 必然在 (wedge 0) 之前(也可以不存在 (vee 1) 和 (wedge 0),因为初始时为 (0))。
但这样还是很难考虑,对模型进行转换。我们发现,插入的每个符号,都对应一个二进制位上的数,除了初始的 (0) 没有符号与之对应。不妨将 (n) 个符号也压缩成一个二进制数,并设 (vee o 0,wedge o 1)。这样设有一个很巧妙的点:当 (vee 0) 或 (wedge 1) 时,按位比较这两个二进制数是一样的,而 (vee 1) 或 (wedge 0) 这些对结果有实质影响的操作,体现在这两个二进制数上就有大小之分。
根据之前的结论,最终运算结果为 (1) 时,最后一个 (vee 1) 必在 (wedge 0) 之后(或者不存在 (wedge 0),只存在 (vee 1))。我们发现将给出的 (n) 个 (1) 位二进制数按 (nsim 1) 从高到低位压缩成一个 (n) 位二进制数 (x)。记 (w) 为操作序列压缩成的二进制数,若 (w<x),那么这一位结果为 (1);否则,若 (wgeq x),这一位结果为 (0)。
上述结论的证明如下:
- 对于 (w eq x) 的情况,根据二进制比较的定义,设 (w) 与 (x) 的 (isim n) 位相等,而在第 (i-1) 位不相等,相等的部分对结果没有影响,只考虑不相等。不相等只存在两种情况,(w) 的第 (i-1) 位为 (0),而 (x) 的第 (i-1) 位为 (1),或 (w) 的第 (i-1) 位为 (1),而 (x) 的第 (i-1) 为 (0)。第一种情况对应了 (vee 1) 晚于 (wedge 0) 的情况,而第二种情况对应了 (wedge 0) 晚于 (vee 1) 的情况。
- 对于第一种情况,(w<x),最终结果为 (1);对于第二种情况,(w > x),最终结果为 (0)。
- 对于 (w=x) 的情况,相等的部分对结果没有影响,因此最终结果为初始的 (0)。
得到上述结论后,对于 (mgeq 2) 的点也非常好想,直接将每一个二进制数拆位,对于每一位得到一个关于 (w) 的不等式,解这个不等式组即可。最终得到 (L leq w < R),答案即为 (R-L),注意对于答案处理边界。
代码写的非常娱乐,对于二进制数排序部分的处理,没有用 ( ext{trie}) 也没有用基排,暴力写了个 ( ext{cmp}) 直接套用 ( ext{sort}),跑的慢死了,看看就好(
#include<cstdio>
#include<algorithm>
typedef long long ll;
const ll mod=1e9+7;
int n;
struct BN {
int id,a[5005];
}input[1005],c[5005];
char s[5005]; int rev[5005];
inline int min(const int &x,const int &y) {return x<y? x:y;}
inline int max(const int &x,const int &y) {return x>y? x:y;}
inline bool cmp(const BN &x,const BN &y) {for(register int i=n;i>=1;--i) {if(x.a[i]<y.a[i]) return 1; if(x.a[i]>y.a[i]) return 0;} return 0;}
signed main() {
int m,q; scanf("%d%d%d",&n,&m,&q);
for(register int i=1;i<=n;++i) {
scanf("%s",s+1);
for(register int j=1;j<=m;++j) input[i].a[j]=s[m-j+1]-'0';
}
for(register int i=1;i<=m;++i) {
for(register int j=n;j>=1;--j) {
c[i].a[j]=input[j].a[i];
}
c[i].id=i;
}
std::sort(c+1,c+1+m,cmp);
for(register int i=1;i<=n;++i) c[m+1].a[i]=1;
for(register int i=1;i<=m;++i) rev[c[i].id]=i;
for(register int t=1;t<=q;++t) {
scanf("%s",s+1); int st=0,ed=m+1;
for(register int i=1;i<=m;++i) {
if(s[i]=='1') {ed=min(ed,rev[m-i+1]);}
else {st=max(st,rev[m-i+1]);}
}
if(!cmp(c[st],c[ed])) {printf("0
");}
else {
ll L=0,R=0;
for(register int i=n;i>=1;--i) L=((L<<1)|(c[st].a[i]))%mod;
for(register int i=n;i>=1;--i) R=((R<<1)|(c[ed].a[i]))%mod;
printf("%lld
",((R+(ed==m+1)-L)%mod+mod)%mod);
}
}
return 0;
}