題目大意:有n個點,m條有向邊,每條邊上有一個小寫字母。c++
有一我的從1號點開始在這個圖上隨機遊走,遊走過程當中他會按順序記錄下走過的邊上的字符。spa
若是在某個時刻,他記錄下的字符串中,存在一個子序列和S2相同,或者存在一個子串和S1相同,那麼他就會當場去世。code
他想知道他會不會當場去世,若是會,他想問你當場去世的時間的指望。blog
數據範圍:n≤20,|S1|≤10,|S2|≤50字符串
咱們考慮列一個dp方程出來it
設f[i][j][k]表示這人從1號點出發,當前走到i號點,且子串覆蓋了S1的前j位,覆蓋了S2的前k位的指望步數class
而後你會發現你作不出來,由於最終根本沒法統計答案(而後你就進死衚衕了)im
咱們嘗試把整個方程反過來統計
設$f[i][j][k]$表示你從$i$號點出發,以前走的路已經覆蓋了$S1$的前$j$位,$S2$串的前$k$位的狀況下,指望走多少部後會去世。nw
最終須要求的答案顯然是$f[1][0][0]$
咱們不難列出$f[i][j][k]=1+\frac{1}{d[i]} \sum\limits_{(i,u)∈E}f[u][j'][k']$
其中$d[i]$表示$i$號點的出度,$E$表示邊集,$j'$和$k'$的具體值視該轉移邊的字母而訂,很是好求。
這個方程咱們顯然能夠經過高斯消元求解,時間複雜度$O(n^3|S1|^3|S2|^3)$,愉快$TLE$
無解的狀況出現即爲某一條方程出現了被零除。
咱們發現,從$f[i][j'][k']$向$f[i][j][k]$轉移的過程當中,有$k'≥k$
那麼咱們顯然能夠固定$k$,對每個$k$作一次高斯消元,而後向下一層傳值,再高斯消元便可。
時間複雜度因而就下降到$O(n^3|S1|^3|S2|)$了
看起來有$4$個億
實際上因不明緣由,每一層須要轉移的節點數根本就去不到理論上屆
因此只跑了不到$20ms$(大霧)
1 #include<bits/stdc++.h> 2 #define M 205 3 #define eps 1e-6 4 using namespace std; 5 6 double f[M][M]={0},ans[M]={0}; 7 8 void gauss(int n){ 9 for(int i=1;i<=n;i++){ 10 int id=i; 11 for(int j=i;j<=n;j++) if(f[id][i]<f[j][i]) id=j; 12 swap(f[i],f[id]); 13 if(fabs(f[i][i])<eps) {printf("-1\n"); exit(0);} 14 for(int j=i+1;j<=n;j++){ 15 double cha=f[j][i]/f[i][i]; 16 for(int k=i;k<=n+1;k++) f[j][k]-=f[i][k]*cha; 17 } 18 } 19 for(int i=n;i;i--){ 20 for(int j=i+1;j<=n;j++) f[i][n+1]-=ans[j]*f[i][j]; 21 ans[i]=f[i][n+1]/f[i][i]; 22 } 23 } 24 25 struct edge{int u,next;char v;}e[600]={0}; int head[M]={0},use=0; 26 void add(int x,int y,char z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;} 27 int n,m; 28 29 char w[M]={0},p[M]={0}; int lenw,lenp; 30 int nxt[M]={0}; 31 32 void upd(char C,int id,int &nowj,int &nowk){ 33 for(;nowj&&w[nowj+1]!=C;nowj=nxt[nowj]); 34 if(w[nowj+1]==C) nowj++; 35 if(p[nowk+1]==C) nowk++; 36 } 37 38 int vis[22][11][55]={0}; 39 void dfs(int i,int j,int k){ 40 if(vis[i][j][k]) return; 41 vis[i][j][k]=1; 42 if(j==lenw||k==lenp) return; 43 for(int l=head[i];l;l=e[l].next){ 44 char C=e[l].v; int id=e[l].u; 45 int nowj=j,nowk=k; 46 upd(C,id,nowj,nowk); 47 dfs(id,nowj,nowk); 48 } 49 } 50 51 int id[22][11]={0},iid[22][11]={0},cnt=0; double d[M]={0}; 52 53 int main(){ 54 scanf("%d%d",&n,&m); 55 for(int i=1;i<=m;i++){ 56 int x,y; char z[10]; scanf("%d%d%s",&x,&y,z); 57 add(x,y,z[0]); d[x]++; 58 } 59 scanf("%s",w+1); lenw=strlen(w+1); 60 scanf("%s",p+1); lenp=strlen(p+1); 61 for(int i=2,j=0;i<=n;i++){ 62 for(;j&&w[j+1]!=w[i];j=nxt[j]); 63 if(w[j+1]==w[i]) j++; 64 nxt[i]=j; 65 } 66 dfs(1,0,0); 67 for(int k=lenp-1;~k;k--){ 68 int cnt=0; 69 for(int i=1;i<=n;i++) 70 for(int j=0;j<lenw;j++){ 71 id[i][j]=0; 72 if(vis[i][j][k]) 73 id[i][j]=++cnt; 74 } 75 memset(f,0,sizeof(f)); 76 for(int i=1;i<=n;i++) 77 for(int j=0;j<lenw;j++) if(id[i][j]){ 78 int ID=id[i][j]; 79 f[ID][ID]=d[i]; 80 f[ID][cnt+1]=d[i]; 81 for(int l=head[i];l;l=e[l].next){ 82 char C=e[l].v; int u=e[l].u; 83 int nowj=j,nowk=k; 84 upd(C,u,nowj,nowk); 85 if(nowj==lenw) continue; 86 if(nowk==k){ 87 f[ID][id[u][nowj]]--; 88 }else{ 89 f[ID][cnt+1]+=ans[iid[u][nowj]]; 90 } 91 } 92 } 93 memcpy(iid,id,sizeof(id)); 94 memset(ans,0,sizeof(ans)); 95 gauss(cnt); 96 } 97 printf("%.10lf\n",ans[1]); 98 }