\(1.\)把操作序列转化为2进制数,手动模拟的时候把相同性质的放到一起考虑(\(1\)和\(|,0\)和\(&\))&;&有的时候也需要把性质不同的放到一起
\(2.\)确定范围只需要通过两个边界
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
}
const int MAXN=5e3+5;
const int mod=1e9+7;
int a[MAXN],b[MAXN],f[MAXN],g[MAXN],pow[MAXN];
char s[MAXN];
int n,m,Q,cnt[2];
int main(){
n=read(),m=read(),Q=read();
pow[0]=1;
for(int i=1;i<=n;i++) pow[i]=(pow[i-1]*2)%mod;
for(int i=1;i<=m;i++) a[i]=i;//初值只要都存在就行了
for(int i=1;i<=n;i++){
scanf("%s",s+1);
cnt[0]=0,cnt[1]=m;
for(int j=1;j<=m;j++)
if(s[j]=='1') f[j]=(f[j]+pow[i-1])%mod;
else cnt[0]++;
for(int j=m;j>=1;j--) b[cnt[s[a[j]]-'0']--]=a[j];//2进制基数排序,先排低位,再排高位
swap(a,b);
}
for(int i=1;i<=m;i++) g[i]=f[a[i]];
g[m+1]=pow[n];
while(Q--){
// x>op --> 1
// x<=op --> 0
// 通过两个临界状态确定范围(还是觉得有点怪)
scanf("%s",s+1);
int up=m+1,down=0;
for(int i=m;i>=1;i--)
if(s[a[i]]=='0'){down=i;break;}//最大的一个要变成0 --> op要大于这个最大数
for(int i=1;i<=m;i++)
if(s[a[i]]=='1'){up=i;break;}//最小的一个要变成1 --> op要小于这个数
if(up<down) printf("0\n");
else printf("%d\n",(g[up]-g[down]+mod)%mod);
}
}
原文:https://www.cnblogs.com/lizehon/p/10533647.html