1444: [Jsoi2009]有趣的游戏
4820: [Sdoi2017]硬币游戏
这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题。
第一题数据范围较小,将串建成AC自动机以后,以AC自动机上每个点为一个未知数,列出方程高斯消元求解即可,时间复杂度$O(n^{3}m^{3})$。
#include<queue> #include<cstdio> #include<algorithm> #define MN 21 #define ld double #define eps 1e-12 using namespace std; struct na{int t[10],bo,f;na(){bo=0;}}t[MN*MN]; int n,m,l,mo[MN],num=0,p[MN],q[MN]; char s[21]; int insert(char s[]){ int i=0,j=0; for (;s[i];j=t[j].t[s[i]-'A'],i++) if (!t[j].t[s[i]-'A']) t[j].t[s[i]-'A']=++num; t[j].bo=1; for (i=0;s[i];i++) if (p[s[i]-'A']==0) return -1; return j; } queue<int> _q; ld a[MN*MN][MN*MN],S; ld abs(ld a){return a<0?-a:a;} inline void Gauss(){ int i,j,k; for (i=0;i<=num;i++){ for (j=i;j<=num;j++) if (abs(a[j][i])>eps) break; for (k=0;k<=num+1;k++) swap(a[i][k],a[j][k]); for (j=0;j<=num;j++) if (j!=i) for (S=a[j][i]/a[i][i],k=0;k<=num+1;k++) a[j][k]-=S*a[i][k]; } } int main(){ register int i,j; scanf("%d%d%d",&n,&l,&m); for (i=0;i<m;i++) scanf("%d%d",&p[i],&q[i]); for (i=0;i<n;i++) scanf("%s",s),mo[i]=insert(s); t[0].f=0; for (i=0;i<m;i++) if (t[0].t[i]) _q.push(t[0].t[i]),t[t[0].t[i]].f=0; while (!_q.empty()){ int k=_q.front();_q.pop(); for (i=0;i<m;i++) if (t[k].t[i]){ for (j=t[k].f;j&&!t[j].t[i];j=t[j].f); t[t[k].t[i]].f=t[j].t[i]; _q.push(t[k].t[i]); } } for (int k=0;k<=num;a[k][k]-=1.,k++) if (!t[k].bo) for (i=0;i<m;i++){ for (j=k;j&&!t[j].t[i];j=t[j].f); j=t[j].t[i]; a[j][k]+=1.*p[i]/q[i]; } a[0][num+1]=-1; Gauss(); for (i=0;i<n;i++) if (mo[i]==-1) puts("0.00");else printf("%.2lf\n",a[mo[i]][num+1]/a[mo[i]][mo[i]]+eps); }