给你n n n 个长度为m m m 的0 1 01 0 1 串
你可以在每个串前面加一个运算符∨ \lor ∨ 或∧ \land ∧
每次询问一个长度为m m m 的0 1 01 0 1 串,问有多少总操作序列能得到这个串
n ≤ 1 0 0 0 , m ≤ 5 0 0 0 , q ≤ 1 0 0 0 n\le1000, m\le 5000, q\le 1000 n ≤ 1 0 0 0 , m ≤ 5 0 0 0 , q ≤ 1 0 0 0
Links Luogu P4424
Solution 按位考虑
通过观察发现,只有形如∣ 1 |1 ∣ 1 或& 0 \&0 & 0 这样的运算才会改变这一位的答案
即最终结果是1 1 1 的充要条件就是最后一个∣ 1 |1 ∣ 1 的位置要在最后一个& 0 \&0 & 0 的后面
于是把操作序列转化成一个0 1 01 0 1 序列∣ → 0 , & → 1 |\rightarrow0, \&\rightarrow1 ∣ → 0 , & → 1
容易发现,在确定这一位最终结果的过程,实际上就是比较操作序列和原串的字典序的过程
那么就很好做了。按字典序排序,对于每个询问找到其对应的上下界(最后一个0 0 0 出现的位置和第一个1 1 1 出现的位置),直接统计答案即可
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 #include <bits/stdc++.h> #define x first #define y second #define y1 Y1 #define y2 Y2 #define mp make_pair #define pb push_back using namespace std ;typedef long long LL;typedef pair<int , int > pii;template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0 ; }template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0 ; }inline void proc_status () { ifstream t ("/proc/self/status" ) ; cerr << string (istreambuf_iterator <char > (t), istreambuf_iterator <char > ()) <<endl ; } inline int read () { int sum = 0 , fl = 1 ; char ch = getchar(); for (; !isdigit (ch); ch = getchar()) if (ch == '-' ) fl = -1 ; for (; isdigit (ch); ch = getchar()) sum = (sum << 3 ) + (sum << 1 ) + ch - '0' ; return sum * fl; } const int Maxn = 1000 + 100 , Maxm = 5000 + 100 , Mod = 1e9 + 7 ;int N, M, Q;int A[Maxm][Maxn], Sum[Maxm], Rank[Maxm];inline int cmp (int a, int b) { for (int i = 1 ; i <= N; ++i) if (A[a][i] > A[b][i]) return 0 ; else if (A[a][i] < A[b][i]) return 1 ; return 0 ; } inline void Add (int &a, int b) { a += b; if (a >= Mod) a -= Mod; }inline void Solve () { static int Pow[Maxn]; Pow[0 ] = 1 ; for (int i = 1 ; i <= N; ++i) Pow[i] = 1l l * Pow[i - 1 ] * 2 % Mod; for (int i = 1 ; i <= M; ++i) reverse (A[i] + 1 , A[i] + N + 1 ); for (int i = 1 ; i <= M; ++i) Rank[i] = i; sort(Rank + 1 , Rank + M + 1 , cmp); for (int i = 1 ; i <= M; ++i) for (int j = 1 ; j <= N; ++j) Add (Sum[i], A[Rank[i]][j] * Pow[N - j]); Sum[M + 1 ] = Pow[N]; while (Q--) { static char S[Maxm]; int pos1 = 0 , pos2 = M + 1 ; scanf ("%s" , S + 1 ); for (int i = M; i >= 1 ; --i) if (S[Rank[i]] == '0' ) {pos1 = i; break ; } for (int i = 1 ; i <= M; ++i) if (S[Rank[i]] == '1' ) {pos2 = i; break ; } printf ("%d\n" , pos1 <= pos2 ? (Sum[pos2] - Sum[pos1] + Mod) % Mod : 0 ); } } inline void Input () { N = read(), M = read(), Q = read(); for (int i = 1 ; i <= N; ++i) { static char S[Maxm]; scanf ("%s" , S + 1 ); for (int j = 1 ; j <= M; ++j) A[j][i] = S[j] - '0' ; } } int main () {#ifdef hk_cnyali freopen("A.in" , "r" , stdin ); freopen("A.out" , "w" , stdout ); #endif Input(); Solve(); return 0 ; }