官方题解:Link

首先考虑暴力,具体来说可以从 SG 函数的角度思考。

如果一个位置可行那么设为 $1$,不可行则设为 $0$。

那么贝茜的操作即取 AND,FJ 的操作即取 OR。

见官方题解图:

image

我们可以逐步确定取牌的策略,即先尝试取 B,检验是否可行,若不可行,取 T,(这样做是因为还有字典序最小的要求)。

暴力检验是 $O(2^{2n})$ 的。

接着我们发现 OR 和 AND 都有短路的性质,即 OR 中出现了一个 $1$ 之后就会停止运算,AND 类似。

我们可以随机的选择先计算哪一颗子树,再运用短路的性质剪枝。我们可以考虑证明这样做的时间复杂度。

设 $f(d)$ 为一颗深度为 $d$ 的子树结果为 $0$ 的计算次数,$t(d)$ 为结果为 $1$ 的计算次数。

注意到德·摩根定律:

$$
P \land Q = \lnot (\lnot P \lor \lnot Q)
$$

所以 AND 与 OR 本质相同,故不妨假设所有操作都在 OR 上。

对于 $f(d)$,根据德·摩根(注意取反)有:

$$
f(d) = 2 t(d-1)
$$

对于 $t(d)$,当我们只有一个 $1$ 子树的时候最劣:

$$
t(d) = f(d-1) + \frac{1}{2} t(d-1)
$$

故:

$$
t(d) = \frac{1}{2} t(d-1) + 2 t(d-2)
$$

所以:

$$
t(d) = (\frac{1+\sqrt{33}}{4})^d
$$

所以检验的时间复杂度是:$O((\frac{1+\sqrt{33}}{4})^{2n})$ 的。

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
#include<bits/stdc++.h>
using namespace std;
const int maxn=15;
mt19937 rnd(time(0));
int n,m,K;
int a[maxn+5][10];
char s[maxn+5];
inline int Calc(int st,int x,int c,int t){
return ((a[st][(c<<2)|(t<<1)]+1ll)*x
+a[st][(c<<2)|(t<<1)|1])%m;
}
bool Check(int st,int x,int c){
int t=rnd()&1;
if(st>(n-1)<<1) return (x<=K)||(-x+m<=K);
if(st&1) return Check(st+1,x,t)||Check(st+1,x,!t);
else{
return Check(st+1,Calc(st>>1,x,c,t),t)
&&Check(st+1,Calc(st>>1,x,c,!t),!t);
}
}
signed main(){
scanf("%d%d%d",&n,&m,&K);
scanf("%s",s);
for(int i=0;i<n;i++)
for(int j=0;j<8;j++)
scanf("%d",&a[i][j]);
int x=0;
for(int i=0;i<n;i++){
if(Check(i<<1,x,1)){
putchar('B');
x=Calc(i,x,1,s[i]=='B');
}
else{
putchar('T');
x=Calc(i,x,0,s[i]=='B');
}
}
return 0;
}