• P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】


    正题

    题目链接:https://www.luogu.com.cn/problem/P3706


    题目大意

    给出 (n) 个长度为 (m)(H/T) 串。

    开始一个空序列,每次随机在后面加一个 (H/T) ,求每个串第一次出现的概率。

    (1leq n,mleq 300)


    解题思路

    数据范围显然不能在AC自动机上高斯消元,所以得考虑别的方法。

    考虑一个很妙的做法,设一个状态(N)表示目前还没有匹配完成的串,然后考虑串(A=HHT)和串(B=THH),那么在(N)后面直接插入一个(A)的概率就是(p(N+A)=p(N) imes 2^{-m})

    但是考虑到有可能(N)先拼出了(B)然后再拼出(A),此时考虑(B)的后缀对应(A)前缀的有(H,HH)。那么就有

    [p(N) imes 2^{-m}=p(N+A)=p(A)+p(B) imes 2^{-2}+p(B) imes 2^{-1} ]

    这样不难发现对于别的串如果它的一些后缀是这个串的前缀那么就会产生一些概率,用字符串(hash)匹配即可。

    然后会发现还是少了一个方程,最后一个就是所有串的概率和为(1)就好了。

    这样就有(n+1)个方程了。

    时间复杂度:(O(n^2m+n^3))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ull unsigned long long
    using namespace std;
    const int N=310;
    const ull g=131;
    int n,m;
    double a[N][N],b[N],pw[N];
    ull h[N][N],p[N];char s[N];
    ull geth(int x,int l,int r)
    {return h[x][r]-h[x][l-1]*p[r-l+1];}
    void Gauss(int n){
    	for(int i=1;i<=n;i++){
    		int z=i;
    		for(int j=i+1;j<=n;j++)
    			if(a[j][i]>a[z][i])z=i;
    		swap(a[i],a[z]);
    		double x=a[i][i];b[i]/=x;
    		for(int j=i;j<=n;j++)a[i][j]/=x;
    		for(int j=i+1;j<=n;j++){
    			double rate=-a[j][i];
    			for(int k=i;k<=n;k++)
    				a[j][k]+=rate*a[i][k];
    			b[j]+=rate*b[i];
    		}
    	}
    	for(int i=n;i>=1;i--){
    		for(int j=1;j<i;j++){
    			b[j]-=a[j][i]*b[i];
    			a[j][i]=0;
    		}
    	}
    	return;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);p[0]=1;pw[0]=1;
    	for(int i=1;i<=m;i++)
    		pw[i]=pw[i-1]*0.5,p[i]=p[i-1]*g;
    	for(int i=1;i<=n;i++){
    		scanf("%s",s+1);
    		for(int j=1;j<=m;j++)
    			h[i][j]=h[i][j-1]*g+s[j];
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			for(int k=1;k<=m;k++)
    				if(geth(i,1,k)==geth(j,m-k+1,m))
    					a[i][j]+=pw[m-k];
    	for(int i=1;i<=n;i++)
    		a[i][n+1]=-pw[m],a[n+1][i]=1;
    	b[n+1]=1;Gauss(n+1);
    	for(int i=1;i<=n;i++)
    		printf("%.12lf
    ",b[i]);
    	return 0;
    }
    
  • 相关阅读:
    剑指Offer-49.把字符串转换成整数(C++/Java)
    codeforces Gym 100338H High Speed Trains (递推,高精度)
    codeforces Gym 100338E Numbers (贪心,实现)
    codeforces Gym 100338C Important Roads (重建最短路图)
    HDU 4347 The Closest M Points (kdTree)
    UVA 10817
    HDU 4348 I
    HDU 4341 Gold miner (分组背包)
    UVA 1218
    UVA 1220 Party at Hali-Bula (树形DP)
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15270666.html
Copyright © 2020-2023  润新知