题目梗概
进行一个NIM游戏。
对于每一堆,出现数字X(1<=X<=100)的概率为ax。
求先手有必胜状态的概率。(堆数<=1e9)
解题思路
首先我们必须知道如果异或和为0为必输状态,否则必胜。
f[i][j] 表示前i堆,异或和为j的概率是多少。
转移关系是一定的。
f[i][jxork]+=f[i−1][j]∗p[k] 。
显然可以构造矩阵优化。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=155;
struct jz{
int n,m;
double x[maxn][maxn];
}ans,w;
double p[maxn];
int n,x;
jz cheng(jz a,jz b){
jz c;
memset(c.x,0,sizeof(c.x));
c.n=a.n;c.m=b.m;
for (int i=0;i<=c.n;i++)
for (int j=0;j<=c.m;j++)
for (int k=0;k<=a.m;k++)
c.x[i][j]+=a.x[i][k]*b.x[k][j];
return c;
}
jz mul(jz w,int b){
jz c;
c.n=127,c.m=127;
for (int i=0;i<128;i++)
for (int j=0;j<128;j++) c.x[i][j]=(i==j);
while(b>0){
if (b%2==1) c=cheng(c,w);
w=cheng(w,w);
b=b>>1;
}
return c;
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
scanf("%d%d",&n,&x);
for (int i=0;i<=x;i++) scanf("%lf",&p[i]);
w.n=127;w.m=127;
for (int i=0;i<128;i++)
for (int j=0;j<=x;j++)
w.x[i][i^j]=p[j];
ans.n=0;ans.m=x;ans.x[0][0]=1;
ans=cheng(ans,mul(w,n));
printf("%.8lf\n",1.0-ans.x[0][0]);
return 0;
}