Guessing the Dice Roll
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1010 Accepted Submission(s): 279
Problem Description
There are N players playing a guessing game. Each player guesses a sequence consists of {1,2,3,4,5,6} with length L, then a dice will be rolled again and again and the roll out sequence will be recorded. The player whose guessing sequence first matches the last L rolls of the dice wins the game.
Input
The first line is the number of test cases. For each test case, the first line contains 2 integers N (1 ≤ N ≤ 10) and L (1 ≤ L ≤ 10). Each of the following N lines contains a guessing sequence with length L. It is guaranteed that the guessing sequences are consist of {1,2,3,4,5,6} and all the guessing sequences are distinct.
Output
For each test case, output a line containing the winning probability of each player with the precision of 6 digits.
Sample Input
3 5 1 1 2 3 4 5 6 2 1 1 2 1 3 1 4 1 5 1 6 1 4 3 1 2 3 2 3 4 3 4 5 4 5 6
Sample Output
0.200000 0.200000 0.200000 0.200000 0.200000 0.027778 0.194444 0.194444 0.194444 0.194444 0.194444 0.285337 0.237781 0.237781 0.239102
Source
n个长度l,由1到6组成的序列,掷骰子,取后l个组成序列,一直到其中一个序列被掷到为止。求每个序列被掷到的概率。
用AC自动机构建状态转移的方式,最多有100种状态。
用A表示转移矩阵,则每一步转移的系数都是1/6.
用P表示答案,X表示原序列概率,则P=(A+A^2+A^3+....+A^n)*X。
因为转移矩阵A收敛,所以A+A^2+A^3+....+A^n=(I-A)^-1
所以(I-A)^-1 * P = X
X=[1.0 0 0 0 0 0....0]
解线性方程组即可解得P
#include <cstdio>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <cmath>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=105,maxk=6,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
db r[maxn][maxn],ans[maxn];
int b[maxn][maxn];
int num;
struct node{
struct node *fail;
struct node *next[maxk];
int cnt,id,l;
void init() {
fail=NULL;
for (int i=0;i<maxk;i++) next[i]=NULL;
cnt=l=0;
id=++num;
}
};
node *a[maxn],*q[maxn];
void insert(int h,node *root,int len) {
node *now=root;
int i;
for (i=0;i<len;i++) {
int pos=b[h][i];
if (now->next[pos]==NULL) {
now->next[pos]=new node;
now->next[pos]->init();
a[num]=now->next[pos];
}
now=now->next[pos];
}
now->cnt++;now->l=h;
}
void buildfail(node *root) {
node *p=root;
int front=0,tail=0,i;
for (i=0;i<maxk;i++) {
if (p->next[i]!=NULL) {
p->next[i]->fail=root;
q[tail++]=p->next[i];
} else p->next[i]=root;
}
while (front<tail) {
p=q[front];
for (i=0;i<maxk;i++) {
if (p->next[i]==NULL)
p->next[i]=p->fail->next[i];
else {
node *x=p->fail;
while (x!=NULL) {
if (x->next[i]!=NULL) {
p->next[i]->fail=x->next[i];
break;
}
x=x->fail;
}
if (p->fail->next[i]->cnt) p->next[i]->cnt++;
q[tail++]=p->next[i];
}
}
front++;
}
}
bool gauss(int size) {
int i,j,k;
for (i=0;i<size;i++) {
k=i;
for (j=i+1;j<size;j++) { //找最大的列主元
if (fabs(r[j][i])>fabs(r[k][i])) k=j;
}
// if (fabs(r[k][i])<1e-9) return false; //fail
for (j=i;j<=size;j++)
swap(r[k][j],r[i][j]);
db t=r[i][i];
for (j=i;j<=size;j++)
r[i][j]/=t;
for (j=0;j<size;j++) {
if (i==j) continue;
db t=r[j][i];
for (k=i;k<=size;k++) {
r[j][k]-=t*r[i][k];
}
}
}
// for (i=size-1;i>=0;i--)
// r[i][size]=r[i][size]/r[i][i];
return true;
}
int main() {
int cas;
scanf("%d",&cas);
while (cas--) {
int n,l,i,j,k;
scanf("%d%d",&n,&l);
node *root=new node;
num=-1;
root->init();
a[0]=root;
for (i=1;i<=n;i++) {
for (j=0;j<l;j++) {
scanf("%d",&b[i][j]);
b[i][j]--;
}
insert(i,root,l);
}
buildfail(root);
mem0(r);
for (j=0;j<=num;j++) {
r[j][j]+=1.0;
if (a[j]->cnt!=0) continue;
for (k=0;k<6;k++)
r[a[j]->next[k]->id][j]-=1.0/6.0;
}
r[0][num+1]=1.0;
db tot=0.0;
gauss(num+1);
for (i=1;i<=num;i++) {
if (a[i]->cnt!=0) {
ans[a[i]->l]=r[a[i]->id][num+1];
tot+=ans[a[i]->l];
}
}
for (i=1;i<=n;i++) {
printf("%.6lf",ans[i]/tot);
if (i!=n) printf(" ");
}
printf("\n");
}
return 0;
}