Guessing the Dice Roll
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1566 Accepted Submission(s): 457
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
2016ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)
#include <bits/stdc++.h>
#define eps 1e-9
using namespace std;
const int mn = 13 * 13;
int n, l;
int nx[mn][10], fail[mn];
bool ed[mn];
int mk[mn];
int root, L;
int newnode()
{
for (int i = 1; i <= 6; i++)
nx[L][i] = -1;
ed[L++] = 0;
return L - 1;
}
void init()
{
L = 0;
root = newnode();
}
void add(int g[], int id)
{
int now = root;
for (int i = 0; i < l; i++)
{
if (nx[now][g[i]] == -1)
nx[now][g[i]] = newnode();
now = nx[now][g[i]];
}
ed[now] = 1;
mk[id] = now;
}
void build_Fail()
{
queue<int> Q;
fail[root] = root;
for (int i = 1; i <= 6; i++)
{
if (nx[root][i] == -1)
nx[root][i] = root;
else
{
fail[nx[root][i]] = root;
Q.push(nx[root][i]);
}
}
while (!Q.empty())
{
int now = Q.front();
Q.pop();
for (int i = 1; i <= 6; i++)
{
if (nx[now][i] == -1)
nx[now][i] = nx[fail[now]][i];
else
{
fail[nx[now][i]] = nx[fail[now]][i];
Q.push(nx[now][i]);
}
}
}
}
double a[mn][mn], x[mn];
void Gauss(int equ, int var)
{
int col = 0, max_r;
for (int k = 0; k < equ && col < var; k++, col++)
{
max_r = k;
for (int 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;
if (k != max_r)
{
for (int 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 (int j = col + 1; j < var; j++)
a[k][j] /= a[k][col];
a[k][col] = 1;
for (int i = 0; i < equ; i++)
if (i != k)
{
x[i] -= x[k] * a[i][col];
for (int j = col + 1; j < var; j++)
a[i][j] -= a[k][j] * a[i][col];
a[i][col] = 0;
}
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
init();
scanf("%d %d", &n, &l);
for (int i = 0; i < n; i++)
{
int g[mn];
for (int j = 0; j < l; j++)
scanf("%d", &g[j]);
add(g, i);
}
build_Fail();
// 构造可胜序列的Fail指针表示状态转移情况
memset(a, 0, sizeof a);
memset(x, 0, sizeof x);
/// 初始化 移项, 变号
for (int i = 0; i < L; i++)
a[i][i] = -1.0;
x[0] = -1.0;
for (int i = 0; i < L; i++)
{
for (int j = 1; j <= 6; j++)
{
if (!ed[i] && nx[i][j] != -1)
a[nx[i][j]][i] += 1.0 / 6;
/// i 可到 t , 第 t 行第 i 项 + 1 / 6
}
}
Gauss(L, L); /// 高斯消元解方程
for (int i = 0; i < n - 1; i++)
printf("%.6lf ", x[mk[i]]);
printf("%.6lf\n", x[mk[n - 1]]);
}
return 0;
}