BZOJ 1444:[JSOI2009]有趣的遊戲
阿新 • • 發佈:2018-12-16
BZOJ 1444:[JSOI2009]有趣的遊戲
首先我們建出Trie圖,然後高斯消元。
我們設\(f_i\)表示經過第\(i\)個點的期望次數:
\[ f_x=\sum i\cdot p_x(i) \]
\(p_x(i)\)表示經過第\(x\)個點\(i\)次的概率。我們設表示一個單詞的節點為關鍵節點,則所有關鍵節點只會經過一次,也就是說\(f_{關鍵}=p_{關鍵}(1)\),也就是我們要求的答案。
\[ \displaystyle f_x=\sum_{y與x相連}rate_{y\Rightarrow x}f_y \]
特別地\(\displaystyle f_1=\sum_{y與1相連}rate_{y\Rightarrow 1}f_y+1\)
\(rate_{y\Rightarrow x}\)就是能從\(y\)走到\(x\)的字母的出現概率。
根據這些等式列方程,再高斯消元就行了。
程式碼:
#include<bits/stdc++.h> #define ll long long #define N 12 #define eps 1e-7 using namespace std; inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} int n,l,m; double rate[26]; double w[N*N][N*N]; char str[N]; namespace AC_automation { int cnt=1; int id[N]; struct trie { int ch[26]; int w,fail; }tr[N*N]; void Insert(char *s,int No) { int len=strlen(s+1),now=1; for(int i=1;i<=len;i++) { int j=s[i]-'A'; if(!tr[now].ch[j]) tr[now].ch[j]=++cnt; now=tr[now].ch[j]; } id[No]=now; tr[now].w=1; } queue<int>q; void build_fail() { q.push(1); while(!q.empty()) { int v=q.front(); q.pop(); for(int i=0;i<26;i++) { if(!tr[v].ch[i]) continue ; int sn=tr[v].ch[i],f=tr[v].fail; while(f&&!tr[f].ch[i]) f=tr[f].fail; if(!f) tr[sn].fail=1; else tr[sn].fail=tr[f].ch[i]; q.push(sn); } } } int find_sn(int now,int j) { while(now&&!tr[now].ch[j]) now=tr[now].fail; return now?tr[now].ch[j]:1; } void build_matrix() { for(int i=1;i<=cnt;i++) { w[i][i]=-1; if(tr[i].w) continue ; else { for(int j=0;j<m;j++) { int sn=find_sn(i,j); w[sn][i]+=rate[j]; } } } w[1][cnt+1]=-1; } } int sum; double ans[N*N]; void Gauss(int n) { for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(fabs(w[i][i])<fabs(w[j][i])) swap(w[i],w[j]); if(fabs(w[i][i])<eps) continue ; for(int j=i+1;j<=n;j++) { double tem=w[j][i]/w[i][i]; for(int k=i;k<=n+1;k++) w[j][k]-=tem*w[i][k]; } } } for(int i=n;i>=1;i--) { if(fabs(w[i][i])<eps) {ans[i]=0;continue ;} for(int j=i+1;j<=n;j++) w[i][n+1]-=w[i][j]*ans[j]; ans[i]=w[i][n+1]/w[i][i]; } } int main() { n=Get(),l=Get(),m=Get(); double a,b; for(int i=0;i<m;i++) { a=Get(),b=Get(); rate[i]=a/b; } for(int i=1;i<=n;i++) { scanf("%s",str+1); AC_automation::Insert(str,i); } AC_automation::build_fail(); AC_automation::build_matrix(); sum=AC_automation::cnt; Gauss(sum); for(int i=1;i<=n;i++) { double a=ans[AC_automation::id[i]]; if(fabs(a)>0.005) cout<<fixed<<setprecision(2)<<a<<"\n"; else cout<<"0.00"<<"\n"; } return 0; }