有一个长度为n的01数列a和一个指针,每次随机将指针移至j,并将aj取反,花费为|i - j|,当数列全0或全1停止,求期望花费。n <= 20
使用期望的线性性,每次只统计i到j的贡献,这样其他位置就没有区分了,压个状态就可以消元了。
#include
#include
#include
#include
#include
#include
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
#define eps 0.000000001
using namespace std;
typedef long long LL;
typedef double DB;
const int M = 330;
int n, m, Q;
DB a[M][M], sum;
vector ans;
void PreWork() {
m = (n - 1) * 16;
DB p1 = 1.0 / n;
Rep(i, 0, 1) {
Rep(j, 0, 1) {
Rep(k, 0, n - 2) {
int s = (k * 4 + i * 2 + j) * 4;
if (!s || s == (n - 2) * 16 + 12) {
Rep(t, 0, 3) a[s + t][s + t] = 1;
continue ;
}
Rep(t, 0, 3) {
a[s + t][s + t] = 1;
a[s + t][s ^ 8] = -p1;
a[s + t][(s ^ 4) + 1] = -p1;
if (k) a[s + t][s - 14] = -p1 * k;
if (k < n - 2) a[s + t][s + 19] = -p1 * (n - 2 - k);
}
a[s][m] = p1;
}
}
}
Rep(i, 1, m - 1) {
int k = i;
while (k < m && fabs(a[k][i]) < eps) k ++;
if (k >= m) { continue ; }
Rep(j, 1, m) swap(a[i][j], a[k][j]);
Rep(j, 1, m - 1) if (i != j && a[j][i]) {
DB z = a[j][i] / a[i][i];
Rep(x, 1, m) a[j][x] -= z * a[i][x];
}
}
}
class BitToggler {
public:
vector expectation(int n0, vector bits, vector pos) {
Q = bits.size(), n = n0;
PreWork();
Rep(T0, 0, Q - 1) {
sum = 0; int num = 0, k, s;
Rep(i, 0, n - 1) num += (bits[T0][i] == '1');
Rep(i, 0, n - 1) {
Rep(j, 0, n - 1) if (i != j) {
if (i == pos[T0]) k = 0;
else if (j == pos[T0]) k = 1;
else if (bits[T0][ pos[T0] ] == '0') k = 2;
else k = 3;
bool x1 = (bits[T0][i] == '1'), x2 = (bits[T0][j] == '1');
s = ((num - x1 - x2) * 4 + x1 * 2 + x2) * 4 + k;
sum += a[s][m] / a[s][s] * abs(i - j);
}
}
ans.push_back(sum);
}
return ans;
}
};