#UOJ 384 luoguP4424 HNOI2018 尋寶遊戲 思維題
阿新 • • 發佈:2018-12-11
題意
- 給你個串,次詢問,每次詢問一個串,問在每個串前新增&或|,有多少種方案使得最後的結果為詢問的串,對取模
這個題看了好久題解才會做… 做題要心靜啊
首先考慮按位處理 對於其中的每一位我們提出來看
首先我們觀察一下位運算的一些性質
這說明如果的話這位的值就和前面的沒關係 同理
這說明如果的話這位的值就和當前位沒關係 同理
那麼我們把運算子變成序列,
那麼如果某一位上的值是的話
那麼它最後一個一定在最後一個前面
是, 是轉化一下就是
運算子序列的字典序小於當前序列
同理那一位是就是字典序大於等於當前序列
那麼這個題目就轉化成了一個求字串字典序的題
直接用就好了 有些細節要注意
注意下詢問全序列,因為我們的區間是前閉後開
但是對於全序列來說全部用操作也是合法的
然後就做完了 複雜度
Codes
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 5000 + 10;
int n, m, q, _pow2[N], flag;
string now[N] , a[N], Que, L, R, tmp;
void Solve() {
for(int i = 0; i < m; ++ i) now[i] = tmp;
for(int i = n; i >= 1; -- i)
for(int j = 0; j < m; ++ j)
now[j][n - i] = a[i][j];
}
int Rank(string S) {
int res = 0;
for(int i = 0; i < n; ++ i)
(res += _pow2[n - i - 1] * (S[i] - '0')) %= mod;
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("4424.in", "r", stdin);
freopen("4424.out", "w", stdout);
#endif
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; ++ i) cin >> a[i];
_pow2[0] = 1; tmp = a[1];
for(int i = 1; i <= N - 5; ++ i) _pow2[i] = _pow2[i - 1] * 2 % mod;
if(n > m) for(int i = 1; i <= n - m; ++ i) tmp += "1";
if(n < m) for(int i = 1; i <= m - n; ++ i) tmp.pop_back();
L = R = tmp; Solve();
for(int cas = 1; cas <= q; ++ cas, flag = 0) {
cin >> Que;
for(int i = 0; i < n; ++ i) L[i] = '0', R[i] = '1';
for(int i = 0; i < m; ++ i) if(Que[i] == '1') flag = 1;
for(int i = 0; i < m; ++ i)
if(Que[i] - '0') R = min(R, now[i]);
else L = max(L, now[i]);
if(L >= R) {puts("0"); continue;}
printf("%d\n", (Rank(R) - Rank(L) + 1 - flag + mod) % mod);
}
return 0;
}