HDU 5955 gauss概率dp+ac自動機
阿新 • • 發佈:2018-11-05
題意:有n個人,每個人猜一個[1,6]長度為L的序列,然後無限制的擲骰子,先擲到的那個序列,那個人就是winner,
問每個人贏得概率。
思路:骰子是擲無限次的,但是有許多狀態是重複的,每一種擲法最終必定是以某一個人的序列結束的,
也就是說,誰都不贏的序列是無窮的,概率趨近於0,所以每個人概率相加是1.
我們可以用ac自動機節點編號當做某種情況的狀態,nxt陣列就是這個狀態轉向的下個狀態。
這樣構造出轉移方程就是
dp[i]=sum(dp[from]); dp[i]是i狀態的概率。
最多100個狀態,gauss求解。
注意,終止態不轉移到任何節點
#include<bits/stdc++.h> using namespace std; int nxt[500010][7], fail[500010], ed[500010], L, id[110]; struct Trie{ int root; int newnode(){ for(int i=1; i<=6; i++) nxt[L][i]=-1; ed[L++]=0; return L-1; } void init(){ L=0; root=newnode(); } void Insert(int buf[], int ii, int len){ int now=root; for(int i=0; i<len; i++){ int v=buf[i]; if(nxt[now][v]==-1) nxt[now][v]=newnode(); now=nxt[now][v]; } id[ii]=now; ed[now]++; } void build(){ queue<int> Q; fail[root]=root; for(int i=1; i<=6; i++){ if(nxt[root][i]==-1) nxt[root][i]=root; else{ fail[nxt[root][i]]=root; Q.push(nxt[root][i]); } } while(!Q.empty()){ int now=Q.front(); Q.pop(); for(int i=1; i<=6; i++) if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else{ fail[nxt[now][i]]=nxt[fail[now]][i]; Q.push(nxt[now][i]); } } } }ac; const int N=110; double a[N][N], x[N]; int equ, var; const double eps=1e-10; int gauss(){ int i, j, k, col, max_r; for(k=0, col=0; k<equ&&col<var; k++, col++){ max_r=k; for(i=k+1; i<equ; i++) if(fabs(a[i][col])>fabs(a[max_r][col])) max_r=i; if(fabs(a[max_r][col])<eps) return 0; if(k!=max_r){ for(j=col; j<var; j++) swap(a[k][j], a[max_r][j]); swap(x[k], x[max_r]); } x[k]/=a[k][col]; for(j=col+1; j<var; j++) a[k][j]/=a[k][col]; a[k][col]=1; for(i=0;i<equ; i++) if(i!=k){ x[i]-=x[k]*a[i][col]; for(j=col+1; j<var; j++) a[i][j]-=a[k][j]*a[i][col]; a[i][col]=0; } } return 1; } int s[20]; int main(){ int T, n, m; scanf("%d", &T); while(T--){ memset(x, 0, sizeof x); memset(a, 0, sizeof a); scanf("%d%d", &n, &m); ac.init(); for(int i=1; i<=n; i++){ for(int j=0; j<m; j++) scanf("%d", s+j); ac.Insert(s, i, m); } ac.build(); x[0]=-1; for(int i=0; i<L; i++){ a[i][i]=-1; if(ed[i]) continue; for(int j=1; j<=6; j++){ a[nxt[i][j]][i]+=1./6; } } var=equ=L; gauss(); for(int i=1; i<n; i++){ printf("%.6lf ", x[id[i]]); } printf("%.6lf\n", x[id[n]]); } return 0; }