题目:https://www.luogu.org/problemnew/show/P3706
题解:https://blog.csdn.net/gjghfd/article/details/80355976
令 ( p_x ) 表示哪个串都没在结尾匹配上的概率,那么在 ( p_x ) 的基础上再出现 m 个特定的字符就能拼出任意一个串了。
但是在再出现 m 个字符的过程中可能已经匹配上了某个串,比如 HTT 和 THT ,想在 ( p_x ) 的基础上出现 THT 拼出第二个串,但如果是 ( p_x ) 里长成 HT 样子的串的话,再出现一个 T 就会以第一个串为结尾结束了。
每个字符出现的概率是一样的。所以可以认为 ( p_x ) 里出现形如 HT 或者 ***HT ( ***HT 没有匹配上一个串) 之类的串的概率是 ( ( frac{1}{2} )^2 ) 。不过不太知道为什么是这样。
所以就有 ( p_x*frac{1}{2^m} = p_i+sumlimits_{j=1}^{n}p_jsumlimits_{l in L_{i,j}}frac{1}{2^{m-l}} ) ,其中 ( L_{i,j} ) 表示 i 的前缀与 j 的后缀可以匹配的长度的集合。
还有一个式子就是 ( sumlimits_{i=1}^{n}p_i = 1 ) ,就能高斯消元了。
可以用哈希求 ( L_{i,j} ) 。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long #define db long double using namespace std; const int N=305,b1=1e9+7,b2=10007,m1=1e9+9,m2=993244853; int n,m,pw[N][2]; bool b[N][N]; db bin[N],a[N][N]; struct Node{ int v0,v1; Node(int a=0,int b=0):v0(a),v1(b) {} bool operator== (const Node &b)const {return v0==b.v0&&v1==b.v1;} }h[N][N]; Node get_h(int i,int j) { int r0=(h[i][m].v0-(ll)h[i][j-1].v0*pw[m-j+1][0])%m1; int r1=(h[i][m].v1-(ll)h[i][j-1].v1*pw[m-j+1][1])%m2; if(r0<0)r0+=m1; if(r1<0)r1+=m2; return Node(r0,r1); } void solve() { pw[0][0]=pw[0][1]=1; for(int i=1;i<=m;i++) { pw[i][0]=(ll)pw[i-1][0]*b1%m1; pw[i][1]=(ll)pw[i-1][1]*b2%m2; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { h[i][j].v0=((ll)h[i][j-1].v0*b1+b[i][j])%m1; h[i][j].v1=((ll)h[i][j-1].v1*b2+b[i][j])%m2; } for(int i=1;i<=n;i++)a[i][0]=-bin[m];//a[][0]:px a[0][n+1]=1;for(int i=1;i<=n;i++)a[0][i]=1;//a[0][]:sum=1 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=m;k++) if(h[i][k]==get_h(j,m-k+1)) a[i][j]+=bin[m-k]; } void gauss() { for(int i=0;i<=n;i++) { int bh=i; for(int j=i+1;j<=n;j++) if(fabs(a[j][i])>fabs(a[bh][i]))bh=j; for(int j=i;j<=n+1;j++)swap(a[i][j],a[bh][j]); db sl=a[i][i]; for(int j=i;j<=n+1;j++)a[i][j]/=sl;// for(int j=1;j<=n;j++) if(j!=i&&fabs(a[j][i])) { sl=a[j][i]; for(int k=i;k<=n+1;k++)a[j][k]-=sl*a[i][k]; } } } int main() { scanf("%d%d",&n,&m); char ch[N]; bin[0]=1;for(int i=1;i<=m;i++)bin[i]=bin[i-1]/2; for(int i=1;i<=n;i++) { scanf("%s",ch+1); for(int j=1;j<=m;j++)b[i][j]=(ch[j]=='H'); } solve(); gauss(); for(int i=1;i<=n;i++) printf("%.10Lf ",a[i][n+1]); return 0; }