洛谷 3706 [SDOI2017]硬币游戏——思路

题目: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+\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;
}

 

posted on 2019-02-20 16:04  Narh  阅读(174)  评论(0编辑  收藏  举报

导航