P4424 [HNOI/AHOI2018]寻宝游戏
太NT了,直接去想DP了,啥都没做出来,三十分滚了。
可以发现 \(x | 1 = 1\),\(x \& 0 = 0\),\(x \& 1 = x\),\(x | 0 = x\)。那么我们可以把操作序列看作是 \(01\) 串。 \(\& \rightarrow 1\),\(| \rightarrow 0\) 那么当操作序列和数字序列相等时,答案不变,恒为初始值。那么我们可以按位拆开来算,第 \(N\) 行 \(j\) 位为最高位,一共 \(N\) 位 \(M\) 个数字。合并不等式范围。
设操作序列为 \(op\),数字序列为 \(x\)。
当 \(op \lt x\) 那么答案为 \(0\) 考虑他们是第 \(i\) 位产生不同且 \(op_i \lt x_i\) 所以 \(op_i = 0,x_i = 1\) 也就是 \(|1\) 所以最后一个必为 \(1\),对于 \(i+1 \text{~} N\) 位因为相等,所以不影响答案。
当 \(op \gt x\) 那么答案为 \(1\) 考虑他们是第 \(i\) 位产生不同且 \(op_i \gt x_i\) 所以 \(op_i = 1, x_i = 0\) 也就是 \(\&0\) 所以最后一个必为 \(0\),对于 \(i+1\text{~}N\) 位因为相等,所以不影响答案。
\[\begin{cases}
upper\_bound = min_{s_i = 1}\{ rk_i \} \\
lower\_bound = max_{s_i = 0}\{ rk_i \}
\end{cases}
\]
所以对于询问串 \(q\) ,如果 \(q_i = 0\) 限定了 \(op\) 的上界,\(q_i=1\) 限定了 \(op\) 的下界。所以用最小的上界减去最大的下界就完了。注意当上届位 \(rk[M+1]\) 时,答案要加 \(1\)。具体看代码。
/*
Name:
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <ctime>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
const ll MAXN = (1LL << 20) + 10, INF = 0x3f3f3f3f3f3f3f3f, MOD = 1e9+7;
ll N, M, Q, rk[MAXN], ord[MAXN], pw[MAXN];
string str, now[MAXN];
bool cmp(ll x, ll y) {return now[x] < now[y];}
ll calc(ll x, ll y) { ll ret = 0;
for (ll i = N-1; ~i; i--) (ret += (now[x][i] - now[y][i] + MOD) % MOD * pw[N-i-1] % MOD) %= MOD;
return x == M+1 ? (ret+1) : ret % MOD;
}
int main() { pw[0] = 1;
for (ll i = 1; i <= MAXN - 10; i++) pw[i] = pw[i-1] * 2 % MOD;
cin >> N >> M >> Q;
for (ll i = 1; i <= N; i++) {
cin >> str;
for (ll j = 1; j <= M; j++) now[j] += str[j-1];
} for (ll i = 1; i <= M; i++) reverse(now[i].begin(), now[i].end());
for (ll i = 1; i <= N; i++) now[0] += '0', now[M+1] += '1';
for (ll i = 1; i <= M+1; i++) ord[i] = i;
sort(ord+1, ord+M+1, cmp); for (ll i = 1; i <= M; i++) rk[ord[i]] = i; //, cout << rk[i] << endl;
while (Q--) {
ll maxn = 0, minn = M+1;
cin >> str;
for (ll i = 0; i < M; i++)
if (str[i] == '0') maxn = max(maxn, rk[i+1]);
else minn = min(minn, rk[i+1]);
printf("%lld\n", maxn > minn ? 0LL : calc(ord[minn], ord[maxn]));
}
return 0;
}
希望我们都有一个光明的未来

浙公网安备 33010602011771号