5285: [Hnoi2018]寻宝游戏
分析:
从下面依次确定运算符号,然后在确定的过程中,需要确定的位数会逐渐减少。比如最后有一个1,如果在从下往上确定了一个or 1,那么再往前可以随便选了。
那么就是要求从下往上,第一个出现的or 1要在and 0之前。如果将这一位上的每一个数字拿出来,从下往上构成一个二进制数a,把and看成1,or看成0,也是从下往上构成一个二进制数b,那么就是要求b<a。
对于最后是0的同样是这样,然后取一下中间可以选的范围即可。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<cctype> #include<set> #include<vector> #include<queue> #include<map> #define fi(s) freopen(s,"r",stdin); #define fo(s) freopen(s,"w",stdout); using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 5005, mod = 1e9 + 7; struct Node{ int a[1005], val, id; } b[N]; int pos[N], n, m; char s[N]; bool cmp(Node A,Node B) { for (int i = n; i >= 1; --i) { if (A.a[i] > B.a[i]) return 1; else if (A.a[i] < B.a[i]) return 0; } return 0; } int main() { n = read(), m = read();int q = read(); for (int i = 1; i <= n; ++i) { scanf("%s", s + 1); for (int j = 1; j <= m; ++j) b[j].a[i] = s[j] - '0'; } for (int j = 1; j <= m; ++j) { for (int i = n; i >= 1; --i) b[j].val = (b[j].val * 2 % mod + b[j].a[i]) % mod; b[j].id = j; } sort(b + 1, b + m + 1, cmp); for (int i = 1; i <= m; ++i) pos[b[i].id] = i; b[0].val = 1; for (int i = 1; i <= n; ++i) b[0].val = (b[0].val * 2) % mod; while (q --) { scanf("%s", s + 1); int L = 0, R = m + 1; for (int i = 1; i <= m; ++i) { if (s[i] == '0') R = min(R, pos[i]); else L = max(L, pos[i]); } if (L > R) puts("0"); else printf("%d ", (b[L].val - b[R].val + mod) % mod); } return 0; }