题目大意:
有一个6面的骰子,有n
(n≤10)
个人每个人猜了一个长度为l
(l≤10)
的序列,不停的掷骰子直到满足一个人的序列则那个人获胜,求每个人获胜的概率。
题解:
由题可知,状态总数最多为100。根据每个人的序列建立AC自动机,根据自动机状态转移构建矩阵
M
。
另一种方法是高斯消元,设增量矩阵为
A
,初始向量为
该题中增量矩阵
A
的幂级数是收敛的,且等于
#include <bits/stdc++.h>
using namespace std;
const int MN = 105;
const int Z = 6;
const int maxlen = 10005;
int gue[11];
typedef long long ll;
class matrix{
public:
int row;
int col;
double m[105][105];
matrix(int r,int c):row(r),col(c){
memset(m,0,sizeof(m));
}
matrix(int n){
memset(m,0,sizeof(m));
row = col = n;
for(int i = 0;i < n;i++){
m[i][i] = 1;
}
}
matrix(){}
matrix operator*(const matrix &b){
matrix ret(row,b.col);
for(int i = 0;i < row;i++){
for(int k = 0;k < col;k++){
for(int j = 0;j < b.col;j++){
ret.m[i][j] += m[i][k]*b.m[k][j];
}
}
}
return move(ret);
}
matrix qpow(ll n){
matrix ret(row);
matrix tmp = *this;
while(n){
if(n&1){
ret = move(ret * tmp);
}
tmp = move(tmp * tmp);
n>>=1;
//tmp.print();
//printf("\n");
}
return move(ret);
}
void print(){
for(int i= 0;i < row;i++){
for(int j =0;j < col;j++){
printf("%f ",m[i][j]);
}
printf("\n");
}
}
}A;
class ACautomaton {
public:
int chd[MN][Z], fail[MN], Q[MN], nn;
int fin[11];
bool Mark[MN];
void Init() {
fail[0] = 0;
memset(chd[0], 0, sizeof(chd[0]));
memset(Mark, false, sizeof(Mark));
nn = 1;
}
void Insert(int id,int l) {
int p = 0;
for(int i = 0;i < l;i++) {
int c = gue[i]-1;
if(!chd[p][c]) {
memset(chd[nn], 0, sizeof(chd[nn]));
chd[p][c] = nn++;
}
p = chd[p][c];
}
fin[id] = p;
Mark[p] = true;
}
void Build() {
int *s = Q, *e = Q;
for(int i = 0; i < Z; i++) {
if(chd[0][i]) {
*e++ = chd[0][i];
fail[chd[0][i]] = 0;
}
}
while(s != e) {
int u = *s++;
for(int i = 0; i < Z; i++) {
int v = chd[u][i];
if(v){
*e++ = v;
int t = fail[u];
while(t && !chd[t][i]) t = fail[t];
fail[v] = chd[t][i];
}
//else{
// int t = fail[u];
// while(t&&!chd[t][i]) t = fail[t];
// chd[u][i] = chd[t][i];
//}
}
}
A = matrix(nn,nn);
for(int i = 0;i < nn;i++){
if(Mark[i]){
A.m[i][i] = 1.0;
}
else{
for(int j = 0;j < Z;j++){
int v = chd[i][j];
if(v){
A.m[v][i] += 1.0/6;
}
else{
int t = fail[i];
while(t && !chd[t][j]) t = fail[t];
v = chd[t][j];
A.m[v][i] = 1.0/6;
}
}
}
}
}
void dfs(int u){
if(Mark[u]){
A.m[u][u] = 1.0;
return ;
}
for(int i = 0;i < Z;i++){
int v = chd[u][i];
if(v){
A.m[v][u] = 1.0/6;
dfs(v);
}
else{
int t = fail[v];
while(t && !chd[t][i]) t = fail[t];
t = chd[t][i];
A.m[t][u] = 1.0/6;
}
}
}
}AC;
int main(){
//freopen("in.txt","r",stdin);
int T,n,l;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&l);
AC.Init();
for(int i = 0;i < n;i++){
for(int j = 0;j < l;j++){
scanf("%d",&gue[j]);
}
AC.Insert(i,l);
}
AC.Build();
//printf("%d\n",AC.nn);
matrix x = matrix(AC.nn,1);
x.m[0][0] = 1;
//A.print();
matrix tmp = A.qpow(1ll<<30);
x = tmp*x;
double tot = 0;
for(int i = 0;i < n;i++){
tot += x.m[AC.fin[i]][0];
}
//printf("%f\n",tot);
for(int i = 0;i < n;i++){
printf("%.6f",x.m[AC.fin[i]][0]/tot);
if(i == n-1) printf("\n");
else printf(" ");
}
}
return 0;
}