洛谷 3706 [SDOI2017]硬币游戏——思路
题目:https://www.luogu.org/problemnew/show/P3706
题解:https://blog.csdn.net/gjghfd/article/details/80355976
令 px 表示哪个串都没在结尾匹配上的概率,那么在 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+\sum\limits_{j=1}^{n}p_j\sum\limits_{l \in L_{i,j}}\frac{1}{2^{m-l}} ,其中 L_{i,j} 表示 i 的前缀与 j 的后缀可以匹配的长度的集合。
还有一个式子就是 \sum\limits_{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\n",a[i][n+1]); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥