QOJ 4832 Telepathy
乍一看好像怎么选都是 \(1 / 2\) 概率。
假设长度为 \(2\),或者可以理解为把串分为了长度为 \(2\) 的一个个小串。
考虑加上一点策略,对于 \(\text{Flim}\),为 \(\texttt{01}\) 就选 \(0 / 1\) 这样的。
感觉好像还是 \(1 / 2\),但是考虑以下例子:
\(\text{Flim}\) 此时是 \(\texttt{10}\),选 \(0\)。
对于 \(\text{Flam}\),\(\texttt{00, 01}\) 选 \(1\),\(\texttt{10, 11}\) 选 \(0\)。
那么能够发现对于 \(\text{Flam}\) 不管选什么都是能匹配上的。
所以发现对于 \(\text{Flim}\) 一个串概率并不一定是 \(1 / 2\),而是可能像上面这样甚至到达了 \(1\)。
进一步的,考虑以下的选取方案:
对于 \(\text{Flim}\),\(\texttt{00, 01, 11}\) 选 \(1\),\(\texttt{10}\) 选 \(0\)。
对于 \(\text{Flam}\),\(\texttt{00, 01}\) 选 \(1\),\(\texttt{10, 11}\) 选 \(0\)。
手玩后能发现对于 \(4\times 4 = 16\) 种情况,有 \(10\) 种匹配成功。
也就是说匹配成功的概率达到了 \(10 / 16 = 62.5\%\)。
以下是打表代码:
#include<bits/stdc++.h>
int c[8], p[8];
// f[] -> 状态对应的选 0 / 1
// 状态: x * 4 + y * 2 + z * 1
// x -> Flim 0; Flam 1
// y, z -> 长度为 2 的串的值
int main() {
int mx = 0;
for (int s = 0; s < (1 << 8); s++) {
for (int i = 0; i < 8; i++) c[i] = s >> i & 1;
int cnt = 0;
for (int x = 0; x < 4; x++) for (int y = 0; y < 4; y++) {
int xa[2] = {x >> 1 & 1, x & 1}, ya[2]= {y >> 1 & 1, y & 1};
cnt += xa[c[4 + y]] == ya[c[x]];
}
if (cnt > mx) mx = cnt, memcpy(p, c, sizeof(p));
}
printf("mx = %d\n", mx);
for (int i = 0; i < 8; i++) printf("%d", p[i]);
return 0;
}
但是这还不够,考虑前面分的是长度为 \(2\) 的小串。
于是再加上一个字符,按长度为 \(3\) 来分,再来看一次结果。
能发现匹配成功的次数达到了 \(44\),概率为 \(44 / 64 = 68.75\%\),能够通过。
打表代码:
// 意义同上
#include<bits/stdc++.h>
int c[16], p[16];
int main() {
int lim = 1;
for (int i = 1; i <= 16; i++, lim *= 3);
int mx = 0;
for (int s = 0; s < lim; s++) {
for (int i = 0, x = s; i < 16; i++) c[i] = x % 3, x /= 3;
int cnt = 0;
for (int x = 0; x < 8; x++) for (int y = 0; y < 8; y++) {
int xa[3] = {x >> 2 & 1, x >> 1 & 1, x & 1}, ya[3]= {y >> 2 & 1, y >> 1 & 1, y & 1};
cnt += xa[c[8 + y]] == ya[c[x]];
}
if (cnt > mx) mx = cnt, memcpy(p, c, sizeof(p));
}
printf("mx = %d\n", mx);
for (int i = 0; i < 16; i++) printf("%d", p[i]);
return 0;
}
据官方题解所说把小串的串长继续拉大概率能接近 \(70\%\),但这个打表程序已经跑不动了。
直接把打表程序得到的对应方案与输入相匹配输出即可。
#include<bits/stdc++.h>
const int maxn = 1e6 + 10, limn = 1e6, limk = 1e5;
int c[16] = {0, 1, 2, 2, 0, 1, 0, 0, 0, 1, 2, 2, 0, 1, 0, 0};
char op[5], s[maxn];
int a[maxn];
int main() {
scanf("%s%*d%*d%s", op, s + 1);
for (int i = 1; i <= limn; i++) a[i] = s[i] - '0';
for (int i = 1; i <= limk * 3; i += 3) printf("%d ", i + c[(op[2] == 'a') * 8 + a[i] * 4 + a[i + 1] * 2 + a[i + 2]]);
return 0;
}

浙公网安备 33010602011771号