HDU 5955 Guessing the Dice Roll(AC自动机,高斯消元,概率生成函数)
作者:互联网
你以为我会写AC自动机?对不起这题的加强版只用哈希还只有40行
说实话概率生成函数是个很古老的方法了。
设字符集大小为m,字符串下标从1开始。
设Fi(x)=∑j=1P(游戏在长度为j的时候玩家i胜利)xj
G(x)=∑j=1P(游戏在长度为j的时候仍未结束)xj
对于每个串Ai,我们在一个未结束的状态后加入它,必定结束,但是结束的时间不同,可能串还没加完就结束了。
所以有:
G(x)(mx)∣Ai∣=∑j=1n∑k=1min(∣Ai∣,∣Aj∣)[Ai,1...k=Aj,∣Aj∣−k+1...∣Aj∣]Fj(x)(mx)∣Ai∣−k
我们O(n3)用哈希算出所有的[Ai,1...k=Aj,∣Aj∣−k+1...∣Aj∣]。
那么第i个玩家胜利的概率为∑j=0P(游戏在长度为j的时候玩家i胜利)=Fi(1)
将上面所有等式用x=1带入可以得到n个方程和n+1个变量(包括G(1))。
然后加入∑i=1nFi(1)=1这个等式就可以高斯消元解方程了。
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]);
}
标签:Guessing,AC,...,Ai,hs,rep,Aj,maxn,高斯消 来源: https://blog.csdn.net/qq_35950004/article/details/106443774