HDU-5955 Guessing the Dice Roll AC自动机+高斯消元
HDU-5955 Guessing the Dice Roll
题意
\(n\)个人,每个人给出一个长度为\(m\)的整数序列,序列中每个数为\(1 \sim 6\)中的一个,用一颗骰子不停的掷,直到骰子掷出的数组成的序列的一个后缀能匹配上某个人的猜测序列,游戏结束,那个人获胜,问每个人获胜的概率。
\(n,m\le 10\)
分析
把每个序列扔进AC自动机建fail树,因为初始状态对应的为空串,所以自动机初始状态的概率设为\(1\),然后设\(a_1,a_2,\dots,a_k\)为可以转移到结点\(i\)的非终止结点,\(x_i\)为结点\(i\)的概率,那么有
\[x_i= \frac{1}{6}x_{a_1}+\frac{1}{6}x_{a_2}+ \dots + \frac{1}{6} x_{a_k}
\]
移项一下得
\[-x_i+\frac{1}{6}x_{a_1}+\frac{1}{6}x_{a_2}+ \dots + \frac{1}{6} x_{a_k}=0
\]
可以对自动机上每个结点都列一个方程,得到一个\(n\)元一次方程组,利用高斯消元解方程即可。
Code
#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e2+10;
const int inf=1e9;
int T,n,m,a[11],b[11];
double A[110][110],ans[110];
struct ACtree{
int son[N][7],fail[N],ed[N],tot;
int newnode(){
for(int i=1;i<=6;i++) son[tot][i]=0;
ed[tot++]=0;
return tot-1;
}
void init(){
tot=0;
newnode();
}
void ins(int x){
int rt=0;
for(int i=0;i<m;i++){
if(!son[rt][a[i]]) son[rt][a[i]]=newnode();
rt=son[rt][a[i]];
}
ed[rt]=1;
b[x]=rt;
}
void gauss(int n){
for(int i=1;i<n;i++){
if(A[i][i]==0){
int id=0;
for(int j=i+1;j<=n;j++)
if(A[j][i]!=0) id=j;
for(int j=i;j<=n+1;j++)
swap(A[i][j],A[id][j]);
}
for(int j=i+1;j<=n;j++){
double t=A[j][i]/A[i][i];
for(int k=i;k<=n+1;k++)
A[j][k]-=(A[i][k]*t);
}
}
for(int i=n;i>=1;i--){
for(int j=i+1;j<=n;j++)
A[i][n+1]-=ans[j]*A[i][j];
ans[i]=A[i][n+1]/A[i][i];
}
}
void gao(){
queue<int>q;
for(int i=1;i<=6;i++) if(son[0][i]) fail[son[0][i]]=0,q.push(son[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
ed[u]|=ed[fail[u]];
for(int i=1;i<=6;i++){
if(son[u][i]){
fail[son[u][i]]=son[fail[u]][i];
q.push(son[u][i]);
}else son[u][i]=son[fail[u]][i];
}
}
memset(A,0,sizeof A);
memset(ans,0,sizeof ans);
A[1][tot+1]=-1.0;
for(int i=0;i<tot;i++){
A[i+1][i+1]=-1.0;
if(ed[i]) continue;
for(int j=1;j<=6;j++){
A[son[i][j]+1][i+1]+=1.0/6;
}
}
gauss(tot);
}
}AC;
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d",&T);
while(T--){
AC.init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int i=0;i<m;i++) scanf("%d",&a[i]);
AC.ins(i);
}
AC.gao();
for(int i=1;i<=n;i++) printf("%.6f%c",ans[b[i]+1],i==n?'\n':' ');
}
return 0;
}