HDU 5955 Guessing the Dice Roll(AC自动机,高斯消元,概率生成函数)

题目
加强版

你以为我会写AC自动机?对不起这题的加强版只用哈希还只有40行
说实话概率生成函数是个很古老的方法了。
设字符集大小为 m m m,字符串下标从1开始。
F i ( x ) = ∑ j = 1 P ( 游 戏 在 长 度 为 j 的 时 候 玩 家 i 胜 利 ) x j F_i(x) = \sum_{j=1} P(游戏在长度为j的时候玩家i胜利)x^j Fi(x)=j=1P(ji)xj
G ( x ) = ∑ j = 1 P ( 游 戏 在 长 度 为 j 的 时 候 仍 未 结 束 ) x j G(x) = \sum_{j=1} P(游戏在长度为j的时候仍未结束)x^j G(x)=j=1P(j)xj
对于每个串 A i A_i Ai,我们在一个未结束的状态后加入它,必定结束,但是结束的时间不同,可能串还没加完就结束了。
所以有:
G ( x ) ( x m ) ∣ A i ∣ = ∑ j = 1 n ∑ k = 1 min ⁡ ( ∣ A i ∣ , ∣ A j ∣ ) [ A i , 1... k = A j , ∣ A j ∣ − k + 1... ∣ A j ∣ ] F j ( x ) ( x m ) ∣ A i ∣ − k G(x)(\frac x{m})^{|A_i|} = \sum_{j=1}^n \sum_{k=1}^{\min(|A_i|,|A_j|)} [A_{i,1...k} = A_{j,|A_j|-k+1...|A_j|}]F_j(x)(\frac xm)^{|A_i|-k} G(x)(mx)Ai=j=1nk=1min(Ai,Aj)[Ai,1...k=Aj,Ajk+1...Aj]Fj(x)(mx)Aik
我们 O ( n 3 ) O(n^3) O(n3)用哈希算出所有的 [ A i , 1... k = A j , ∣ A j ∣ − k + 1... ∣ A j ∣ ] [A_{i,1...k} = A_{j,|A_j|-k+1...|A_j|}] [Ai,1...k=Aj,Ajk+1...Aj]
那么第 i i i个玩家胜利的概率为 ∑ j = 0 P ( 游 戏 在 长 度 为 j 的 时 候 玩 家 i 胜 利 ) = F i ( 1 ) \sum_{j=0} P(游戏在长度为j的时候玩家i胜利) = F_i(1) j=0P(ji)=Fi(1)
将上面所有等式用 x = 1 x=1 x=1带入可以得到 n n n个方程和 n + 1 n+1 n+1个变量(包括 G ( 1 ) G(1) G(1))。
然后加入 ∑ i = 1 n F i ( 1 ) = 1 \sum_{i=1}^n F_i(1) = 1 i=1nFi(1)=1这个等式就可以高斯消元解方程了。

A C   C o d e \mathcal AC \ Code AC Code

#include<bits/stdc++.h>
#define maxn 305
#define LL long long
#define db double
#define S 131ll
#define eps 1e-13
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n,m;
char s[maxn][maxn];
LL hs[maxn][maxn],pw[maxn];
LL calc(LL *hs,int a,int b){ return hs[b] - hs[a-1] * pw[b-a+1]; }
db a[maxn][maxn],pw2[maxn];

int main(){
	scanf("%d%d",&n,&m);
	pw[0] = pw2[0] = 1;
	rep(i,1,max(n,m)) pw[i] = pw[i-1] * S , pw2[i] = pw2[i-1] * 2;
	rep(i,1,n){
		scanf("%s",s[i]+1);
		rep(j,1,m) hs[i][j] = hs[i][j-1] * S + s[i][j];
	}
	rep(i,1,n) a[0][i] = 1 , a[i][0] = 1;a[0][n+1] = 1;
	rep(i,1,n) rep(j,1,n) rep(k,1,m) if(calc(hs[i],1,k) == calc(hs[j],m-k+1,m))
		a[i][j] -= pw2[k];
	rep(i,0,n){
		rep(j,i+1,n) if(fabs(a[j][i]) > fabs(a[i][i])) swap(a[j],a[i]);
		rep(j,i+1,n){
			db t = a[j][i] / a[i][i];
			rep(k,i,n+1)
				a[j][k] -= a[i][k] * t;
		}
	}
	per(i,n,0){
		rep(j,i+1,n) a[i][n+1] -= a[i][j] * a[j][n+1];
		a[i][n+1] /= a[i][i];
	}
	rep(i,1,n) printf("%.10lf\n",a[i][n+1]);
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值