- 题意:有一个 (n) 堆石子的 (nim) 游戏,石子数量从 (0) 到 (x) 有一个概率 (p_i) ,代表了一堆石子数量为 (i) 的数量。求先手必赢的概率。
- 题解:首先nim显然的是 (nim) 异或和为 (0) 是必输,然后可以构造 (A) 矩阵
(A =egin{bmatrix} p[0 oplus 0 ] &p[0 oplus 1] & p[0 oplus 2]\ p[1 oplus 0 ] &p[1 oplus 1] & p[1 oplus 2]\ p[2 oplus 0 ] &p[2 oplus 1] & p[2 oplus 2] end{bmatrix})
(ans) 矩阵就是 (ans = egin{bmatrix}
dp[0] &0 & 0\
dp[1] &0 & 0\
dp[2] &0 & 0
end{bmatrix})
(ans_{1, j}) 代表的意思是,在这一次,(dp[j]) ,即游戏出现他们异或和为(j) 情况的概率。
- 代码:
#include<bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
typedef long double ld;
const ll N = 129;
const ll inf = 0x3f3f3f3f;
ld pp[N];
const ll maxn = 10;
struct Matrix {
ld a[maxn][maxn];
int n;
Matrix (int sz, int kind) {
this->n = sz;
for (int i = 0; i < sz; i ++) {
for (int j = 0; j < sz; j ++) {
a[i][j] = 0;
}
}
for (int i = 0; i < sz; i ++) {
a[i][i] = kind;
}
}
Matrix operator*(Matrix rhs)const {
Matrix ret(N - 1, 0);
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j ++) {
for (int k = 0; k < n; k ++) {
ret.a[i][j] += a[i][k] * rhs.a[k][j];
}
}
}
return ret;
}
void out() {
for (int i = 0; i < 5 ;i ++) {
for (int j = 0; j < 5; j ++) {
cout << a[i][j] << " ";
}
cout << endl;
}
}
} A(maxn - 1, 0);
Matrix q_pow( int k) {
Matrix ret = {N - 1, 1};
Matrix x = A;
while (k) {
if (k & 1) {
ret = ret * x;
}
k >>= 1;
x = x * x;
}
return ret;
}
void solve() {
int n, x;
cin >> n >> x;
for (int i = 0; i <= x; i ++) {
cin >> pp[i];
}
cout << fixed<<setprecision(10);
for (int i = 0; i <= N-2; i ++) {
for (int j = 0; j <= N-2; j ++) {
A.a[i][j] = pp[j ^ i];
}
}
Matrix res = q_pow( n);
Matrix d = Matrix(N - 1, 0);
d.a[0][0] = 1;
res = d * res;
cout << 1.0-res.a[0][0] << endl;
}
signed main() {
ll t = 1;//cin >> t;
while (t--) {
solve();
}
}