题解「HNOI2018 寻宝游戏」
不是很像 \(\text{CN}\) 省选的题,个人感觉更像是 \(\text{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\to 0,\wedge\to 1\)。这样设有一个很巧妙的点:当 \(\vee 0\) 或 \(\wedge 1\) 时,按位比较这两个二进制数是一样的,而 \(\vee 1\) 或 \(\wedge 0\) 这些对结果有实质影响的操作,体现在这两个二进制数上就有大小之分。
根据之前的结论,最终运算结果为 \(1\) 时,最后一个 \(\vee 1\) 必在 \(\wedge 0\) 之后(或者不存在 \(\wedge 0\),只存在 \(\vee 1\))。我们发现将给出的 \(n\) 个 \(1\) 位二进制数按 \(n\sim 1\) 从高到低位压缩成一个 \(n\) 位二进制数 \(x\)。记 \(w\) 为操作序列压缩成的二进制数,若 \(w<x\),那么这一位结果为 \(1\);否则,若 \(w\geq x\),这一位结果为 \(0\)。
上述结论的证明如下:
- 对于 \(w\neq x\) 的情况,根据二进制比较的定义,设 \(w\) 与 \(x\) 的 \(i\sim 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\)。
得到上述结论后,对于 \(m\geq 2\) 的点也非常好想,直接将每一个二进制数拆位,对于每一位得到一个关于 \(w\) 的不等式,解这个不等式组即可。最终得到 \(L \leq w < R\),答案即为 \(R-L\),注意对于答案处理边界。
代码写的非常娱乐,对于二进制数排序部分的处理,没有用 \(\text{trie}\) 也没有用基排,暴力写了个 \(\text{cmp}\) 直接套用 \(\text{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\n");}
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\n",((R+(ed==m+1)-L)%mod+mod)%mod);
}
}
return 0;
}

浙公网安备 33010602011771号