贺了一遍题解/kk
题目大意.
你手上有一个二进制数
,这个数会经历若干次以下操作
- 对于每一位,有
的概率不变,有 的概率变为 ,有 的概率变为 。 对于每个
,求:期望经过多少次操作能首次回到 。
。保证你在计算过程中不需要求 的乘法逆。
首先直接写出这个随机游走过程的方程。记
说人话就是:"所有未结束的路径去掉最后一步一定也是未结束的路径;而一条未结束的路径再走一步要么结束要么不结束"。
也即
顺带一提,这里看似只有
我们知道,
于是
从而,
于是问题变为求
也就是
然后我们来仔细分析转移矩阵的性质,它应当是
其中
如果只有
然而我们如果仔细看一眼这个矩阵,就能发现一些有趣的事情:

其中蓝色的是首次出现的块,不能从前面的计算中继承;其他的块都是继承来的。可见每行最多被分为
好的,现在回到
具体来说:我们知道多项式的高次幂问题可以考虑对角化,而 Kronecker 积也是如此。我们有
设
记
于是我们用
妈的好像推错了,可能哪里行和列搞反了。被我瞎搞一通后这份代码能过。
xusing namespace std;
const int p = 998244353;struct Z {int x; Z(int x0 = 0) : x(x0) {}};int inline check(int x) { return x >= p ? x - p : x; }Z operator +(const Z a, const Z b) { return check(a.x + b.x); }Z operator -(const Z a, const Z b) { return check(a.x - b.x + p); }Z operator -(const Z a) {return check(p - a.x);}Z operator *(const Z a, const Z b) { return 1LL * a.x * b.x % p; }Z& operator +=(Z &a, const Z b) { return a = a + b; }Z& operator -=(Z &a, const Z b) { return a = a - b; }Z& operator *=(Z &a, const Z b) { return a = a * b; }Z qpow(Z a, int k) { Z ans = 1; for (; k; a *= a, k >>= 1) if(k & 1) ans *= a; return ans;}
int n;Z kq; Z kp[20];
Z x[1 << 20];Z ans[1 << 20][20];
int main() { scanf("%d%d", &n, &kq); for (int i = 0; i < n; i++) scanf("%d", &kp[i]); for (int s = 0; s < 1 << n; s++) { if (s == 0) { x[s] = 1; for (int i = 0; i < n; i++) ans[s][i] = kq; continue; } Z qaq = 1, sum = 0; for (int i = 0; i < n; i++) if ((s >> i) & 1) qaq *= kp[i]; for (int i = 0; i < n; i++) if ((s >> i) & 1) sum += ans[s ^ (1 << i)][i] * (1 - kp[i]); x[s] = sum * qpow(1 - qaq, p - 2); ans[s][0] += x[s] * kq * qaq; for (int i = 0; i < n; i++) { if (i) ans[s][i] += ans[s][i - 1]; if ((s >> i) & 1) ans[s][i] += ans[s ^ (1 << i)][i] * (1 - kp[i]); } } // for (int s = 0; s < 1 << n; s++) // if (s < (((1 << n) - 1) ^ s)) swap(x[s], x[(((1 << n) - 1) ^ s)]);
for (int i = 0; i < n; i++) for (int s = 0; s < 1 << n; s++) if (!((s >> i) & 1)){ Z a0 = x[s], a1 = x[s | (1 << i)]; x[s] = a1, x[s | (1 << i)] = a0 - a1; }
Z sx = 0; for (int s = 0; s < 1 << n; s++) sx += x[s]; int ans = 0; Z qaq = 1; for (int s = 0; s < 1 << n; s++, qaq *= 2004) ans ^= (qaq * sx * qpow(s[x], p - 2)).x; printf("%d\n", ans);}