日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)

發布時間:2025/3/15 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

誒這題洛谷居然沒有???

題目鏈接: https://www.lydsy.com/JudgeOnline/problem.php?id=1444

題解: 我見到主要有兩種做法。

一是矩陣乘法。設\(dp[t][i]\)表示時間\(t\)之后在AC自動機\(i\)節點的概率,那么轉移是一個矩陣乘法的形式,構造轉移矩陣\(f\), 如果\(u\)是某個串的結尾點,則\(f[u][u]=1,f[u][v]=0 (v\ne u)\), 否則直接按概率搞。

然后這個矩陣的\(t\)次冪就可以得到\(t\)時刻后在每個點的概率。但是這題時間到無窮。

可以感覺到隨著\(t\)的增加不匹配任何串的概率不斷減小,\(t\)無窮大時達到0. 而題目精度要求并不高,所以如果我們能夠使得\(t\)非常大而精度誤差被控制在要求范圍內,就做完了。

非常粗略地估算一下,\(t=10^{12}\)時矩陣每一項的精度誤差遠小于\(1\times 10^{-4}\) (別問我怎么算的,我放縮的幅度太大了,實際的界應該小于\(10^{12}\))

所以把矩陣自乘\(40\)次就完了。時間復雜度\(O(n^6\times 40)\) (所有范圍為\(10\)的參數不加以區分)

二是高斯消元。

對于任何節點\(u\), 其概率等于所有入邊的概率乘上其字母權值之和,然后這樣可以列出\(siz\) (AC自動機大小)個方程,但是如果這么解的話得到的答案是所有未知數全等于\(0\), 然后就把根的方程去掉,改成所有結束節點的概率之和等于\(1\), 解出來就A掉了……

完全不理解他是要干什么,拿某些題解代碼一看,發現有的點解出來概率都是\(2\)……

到最后終于翻到一篇詳細解釋這個做法的題解: 如果設概率直接拿方程列上會全得\(0\), 原來這個未知數設的并非概率,而是經過該點的期望次數(對于結束節點期望次數就等于概率),然后\(x_0\) (\(0\)為根)等于所有入邊概率之和\(+1\) (因為上來先到一次), 其余節點等于所有入邊概率之和即可解。也可以不要根的那個等式,換成所有結束節點期望次數之和為\(1\), 應該是等價的。(天哪看了一晚上終于看懂了……)

時間復雜度\(O(n^6)\)

據說還有一個枚舉每個人的\(O(n^7)\)做法……大佬們太強了我啥都看不懂啊

三是矩陣求逆,這個貌似(對我來說)還好理解一些……

矩陣第\(i\)行第\(j\)列是從\(i\)轉移到\(j\)的概率,結尾節點的這一行全部為0. 這個和做法一的區別就是結尾節點轉移到自己的概率不是\(1\), 那么原來要求\(T^{+\inf}\)現在就變成要求\(T+T^2+T^3+...+T^{+\inf}\), 這個矩陣元素都小于\(1\)應該收斂的,那么直接求\(T\times (1-T)^{-1}\)即可。

時間復雜度\(O(n^6)\)

代碼

做法一

#include<cstdio> #include<cstdlib> #include<cstring> using namespace std;const int N = 10; const int S = 10; const int LEN = 10; const int SIZ = 100; const int LGM = 40; int son[SIZ+3][S+3]; int fail[SIZ+3]; int que[SIZ+3]; double p[N+3]; int id[N+3]; char a[N+3][LEN+3]; int n,len,s,siz;struct Matrix {double a[SIZ+3][SIZ+3];Matrix operator *(const Matrix &arg) const{Matrix ret;for(int i=0; i<=siz; i++) for(int j=0; j<=siz; j++) ret.a[i][j] = 0.0;for(int i=0; i<=siz; i++){for(int k=0; k<=siz; k++){for(int j=0; j<=siz; j++){ret.a[i][j] += a[i][k]*arg.a[k][j];}}}return ret;} } f;void insertstr(char str[],int sid) {int u = 0;for(int i=1; i<=len; i++){if(son[u][str[i]]==0) {siz++; son[u][str[i]] = siz;}u = son[u][str[i]];}id[sid] = u; }void buildACA() {int head = 1,tail = 0;for(int i=1; i<=s; i++){if(son[0][i]) {tail++; que[tail] = son[0][i];}fail[son[0][i]] = 0;}while(head<=tail){int u = que[head]; head++;for(int i=1; i<=s; i++){if(son[u][i]) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = son[u][i];}else {son[u][i] = son[fail[u]][i];}}} }int main() {scanf("%d%d%d",&n,&len,&s);for(int i=1; i<=s; i++){double x,y; scanf("%lf%lf",&x,&y); p[i] = x/y;}for(int i=1; i<=n; i++){scanf("%s",a[i]+1); for(int j=1; j<=len; j++) a[i][j]-=64;insertstr(a[i],i);}buildACA();for(int u=0; u<=siz; u++){for(int i=1; i<=s; i++){int v = son[u][i];f.a[u][v] += p[i];}}for(int i=1; i<=n; i++){int u = id[i];for(int j=0; j<=siz; j++) f.a[u][j] = (u==j) ? 1.0 : 0.0;}for(int i=1; i<=LGM; i++){f = f*f;}for(int i=1; i<=n; i++) printf("%.2lf\n",f.a[0][id[i]]);return 0; }

總結

以上是生活随笔為你收集整理的BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。