題意:有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;
}