hdu 5995 Guessing the Dice Roll(AC自动机+矩阵)

题目链接:hdu 5995 Guessing the Dice Roll

题意:

有一个6面的骰子,有n(n≤10)个人每个人猜了一个长度为l(l≤10)的序列,不停的掷骰子直到满足一个人的序列则那个人获胜,求每个人获胜的概率。

题解:

将他们猜的串插入AC自动机,然后转移k次,这里k要足够大才能收敛,然后因为总节点数最多才60个,所以用矩阵来加速。

正解应该是用高斯消元来做这个事情。

 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 4 using namespace std;
 5
 6 const int AC_N=100,tyn=6;
 7 int s[20],t,n,l,now,all;
 8 double ans[20];
 9 const int mat_N=105;
10
11 struct mat{
12     double c[mat_N][mat_N];
13     void init(){mst(c,0);}
14     mat operator*(mat b){
15         mat M;int N=all;M.init();
16         F(i,0,N)F(j,0,N)if(c[i][j]!=0)F(k,0,N)M.c[i][k]+=c[i][j]*b.c[j][k];
17         return M;
18     }
19     mat operator^(int k){
20         mat ans,M=(*this);int N=all;ans.init();
21         F(i,0,N)ans.c[i][i]=1;
22         while(k){if(k&1)ans=ans*M;k>>=1,M=M*M;}
23         return ans;
24     }
25 }A;
26
27 struct AC_automation{
28     int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot;
29     inline int getid(int x){return x-1;}
30     void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));}
31     void init(){tot=-1,fail[0]=-1,nw();}
32     void insert(int *s,int len,int idx,int x=0){
33         for(int i=0,w;i<len;x=tr[x][w],i++)
34             if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot;
35         cnt[x]=idx;
36     }
37     void build(int head=1,int tail=0){
38         for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i];
39         while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++)
40             if(tr[x][i])
41             {
42                 fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i];
43                 cnt[tr[x][i]]+=cnt[tr[fail[x]][i]];
44             }
45             else tr[x][i]=tr[fail[x]][i];
46     }
47     void solve()
48     {
49         A.init(),all=tot;
50         F(j,0,tot)
51         {
52             if(cnt[j])A.c[j][j]=1;
53             else F(k,0,5)A.c[tr[j][k]][j]+=1.0/6;
54         }
55         A=A^(1<<30);
56         F(i,0,tot)if(cnt[i])ans[cnt[i]]=A.c[i][0];
57         F(i,1,n)printf("%.6f%c",ans[i]," \n"[i==n]);
58     }
59
60 }AC;
61
62 int main(){
63     scanf("%d",&t);
64     while(t--)
65     {
66         scanf("%d%d",&n,&l);
67         AC.init();
68         F(i,1,n)
69         {
70             F(j,0,l-1)scanf("%d",s+j);
71             AC.insert(s,l,i);
72         }
73         AC.build(),AC.solve();
74     }
75     return 0;
76 }

高斯消元版:

 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 4 using namespace std;
 5 const int AC_N=100,tyn=6;
 6 int s[20],t,n,l,now,all;
 7
 8 #define eps 1e-9
 9 const int MAXN=220;
10 double a[MAXN][MAXN],x[MAXN],ans[MAXN];
11 int equ,var;
12
13 int Gauss()
14 {
15     int i,j,k,col,max_r;
16     for(k=0,col=0;k<equ&&col<var;k++,col++)
17     {
18         max_r=k;
19         for(i=k+1;i<equ;i++)
20             if(fabs(a[i][col])>fabs(a[max_r][col]))
21                 max_r=i;
22         if(fabs(a[max_r][col])<eps)return 0;
23         if(k!=max_r)
24         {
25             for(j=col;j<var;j++)
26               swap(a[k][j],a[max_r][j]);
27             swap(x[k],x[max_r]);
28         }
29         x[k]/=a[k][col];
30         for(j=col+1;j<var;j++)a[k][j]/=a[k][col];
31         a[k][col]=1;
32         for(i=0;i<equ;i++)if(i!=k)
33         {
34             x[i]-=x[k]*a[i][k];
35             for(j=col+1;j<var;j++)a[i][j]-=a[k][j]*a[i][col];
36             a[i][col]=0;
37         }
38     }
39     return 1;
40 }
41
42 struct AC_automation{
43     int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot;
44     inline int getid(int x){return x-1;}
45     void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));}
46     void init(){tot=-1,fail[0]=-1,nw();}
47     void insert(int *s,int len,int idx,int x=0){
48         for(int i=0,w;i<len;x=tr[x][w],i++)
49             if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot;
50         cnt[x]=idx;
51     }
52     void build(int head=1,int tail=0){
53         for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i];
54         while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++)
55             if(tr[x][i])
56             {
57                 fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i];
58                 cnt[tr[x][i]]+=cnt[tr[fail[x]][i]];
59             }
60             else tr[x][i]=tr[fail[x]][i];
61     }
62     void solve()
63     {
64         mst(a,0),mst(x,0),equ=var=tot+1;
65
66         F(j,0,tot)
67         {
68             a[j][j]=-1,x[j]=0;
69             if(!cnt[j])F(k,0,5)a[tr[j][k]][j]+=1.0/6;
70         }
71         x[0]=-1;
72         Gauss();
73         F(i,0,tot)if(cnt[i])ans[cnt[i]]=x[i];
74         F(i,1,n)printf("%.6f%c",ans[i]," \n"[i==n]);
75     }
76
77 }AC;
78
79 int main(){
80     scanf("%d",&t);
81     while(t--)
82     {
83         scanf("%d%d",&n,&l);
84         AC.init();
85         F(i,1,n)
86         {
87             F(j,0,l-1)scanf("%d",s+j);
88             AC.insert(s,l,i);
89         }
90         AC.build(),AC.solve();
91     }
92     return 0;
93 }

时间: 2024-10-28 20:34:29

hdu 5995 Guessing the Dice Roll(AC自动机+矩阵)的相关文章

hdu 5955 Guessing the Dice Roll 【AC自动机+高斯消元】

hdu 5955 Guessing the Dice Roll [AC自动机+高斯消元] 题意:给出 n≤10 个长为 L≤10 的串,每次丢一个骰子,先出现的串赢,问获胜概率. 题解:裸的AC自动机,求匹配到终止结点的概率,用 高斯消元?一开始不知道怎么建方程组,直接举个例子吧: Input: 1 2 2 1 1 2 1 图解: x0原本概率就是1,然后还要加上其他结点走向它的概率,,这样最后算下来是大于1的,现在还是觉得怪怪的... 1 #include <cstdio> 2 #inclu

HDU 5966 Guessing the Dice Roll

题意有 N≤10 个人,每个猜一个长度为L≤10的由1?6构成的序列,保证序列两两不同.不断地掷骰子,直到后缀与某人的序列匹配,则对应的人获胜.求每个人获胜的概率. 思路:建立trie图,跑高斯消元.高斯消元每个点的意义是:第i行第j列的值为x 有概率x从点j转移过来 1 const double eps = 1e-9; 2 const int SIGMA_SIZE = 7; 3 const int MAXNODE = 200; 4 5 int ch[MAXNODE][SIGMA_SIZE];

hdu5955 Guessing the Dice Roll【AC自动机】【高斯消元】【概率】【待补...】

2016沈阳区域赛http://acm.hdu.edu.cn/showproblem.php?pid=5955 Guessing the Dice Roll Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1632    Accepted Submission(s): 480 Problem Description There are N

HDU 3065 病毒侵袭持续中 AC自动机题解

其实本题比HDU的病毒侵袭1还简单,不过有一个陷阱卡到我了:就是搜索text的时候,当遇到的字母不是大写字母的时候,那么就要重新从根节点开始搜索,否则就会答案错误. 那么一点陷阱,居然没想到啊. 教训啊:看来对不太平常的地方,需要更加深入的思考,才能发现其中的陷阱,否则就WA了. #include <stdio.h> #include <string.h> #include <queue> using std::queue; const int MAX_N = 1001

hdu 2243 AC自动机 + 矩阵快速幂

// hdu 2243 AC自动机 + 矩阵快速幂 // // 题目大意: // // 给你一些短串,问在长度不超过k的任意串,包含至少一个这些短串的其中 // 一个.问这样的串有多少个. // // 解题思路: // // 首先, 包含和不包含是一种互斥关系,包含+不包含 = 全集u.全集的答案就是 // 26 ^ 1 + 26 ^ 2 + .... + 26 ^ k.不包含的比较好求.构建一个自动机,得到 // 一个转移矩阵A.表示状态i能到状态j的方法数.而这些状态中都是不包含所给的 //

HDU 3341 Lost&#39;s revenge(AC自动机+状压DP)

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 4548    Accepted Submission(s): 1274 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

hdu 3056 病毒侵袭持续中 AC自动机

http://acm.hdu.edu.cn/showproblem.php?pid=3065 刘汝佳的模板真的很好用,这道题直接过 学到: cnt数组记录单词出现次数 以及map存储单词编号与字符串,便于处理相关信息 上代码: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <queue> #include <str

HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)

题目链接:考研路茫茫――单词情结 做本题前,个人建议先做一下POJ 2778 http://blog.csdn.net/u013446688/article/details/47378255 POJ2778 是求长度为n,不包含模式串的字符串个数. 而本题是求长度为n,包含模式串的字符串个数.直接用字符串总数减去不包含模式串的字符串个数即为所求. 同样是AC自动机 + 矩阵快速幂.但是还是有所不同的. 因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现

hdu2243 ac自动机+矩阵连乘

http://acm.hdu.edu.cn/showproblem.php?pid=2243 Problem Description 背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表示"相反,变坏,离去"等. 于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢.更确切的描述是:长度不超过L,只由小写字母组成的,至少包