luogu3706 硬幣遊戲

2022-06-07 08:00:16 字數 1735 閱讀 7082

(可以參考洛谷4548,推導過程較為省略)

定義$g_$表示隨機$i$次後未出現給定字串的概率,$f_$表示隨機$i$次後恰好出現$s_$(指第$k$個字串)的概率,設兩者的生成函式分別為$g(x)$和$f_(x)$

同樣,考慮如何去表示$p(前i個字元中未出現給定字串且最後m個字元為s_)$:

1.通過$g_$,此時即為$\frac}}$;

2.通過$f_$(注意雖然最後$m$個字元為$s_$,但可能之前$s_$出現了),列舉第乙個出現$s_$的位置$i+j$(右端點),同時必然要有$s_$的前$j$個字元等於$s_$末尾$j$個字元,此時轉移的係數為$\frac}$

記$s_=\[0,j)=s_[m-j,m)\}$,兩者相等即$\forall 1\le t\le n,\frac}}=\sum_^\sum_}\frac}}$,寫成生成函式的形式即$\forall 1\le t\le n,g(x)=\sum_^\sum_}\fracf_(x)}}$

關於$s_$的計算可以使用ac自動機或雜湊,複雜度為$o(n^m)$(雖然ac自動機可以$o(nm)$構建,但列舉$j$還是要$o(n^m)$的)

答案即求$f_(1)$,代入$x=1$後可以得到$n$個等式,但同時新增$g(1)$,再利用$\sum_^f_(1)=1$就是恰好$n+1$個等式和變數,高斯消元即可,時間複雜度為$o(n^)$

(**中的寫法是以$g(1)$為常數去表示$f_(1)$,再累加求出$g(1)$)

(另外精度問題很是神奇,可能資料中$n$和$m$的並不太大?)

1 #include2

using

namespace

std;

3#define n 305

4#define eps 1e-10

5 vectorv[n];

6 queueq;

7int v,n,m,nex[n*n],len[n*n],ch[n*n][31];8

double sum,mi[n],vis[n*n],a[n][n],ans[n];

9char

s[n];

10void add(int

p)17 k=ch[k][(s[i]=='t'

)];18

v[p].push_back(k);19}

20}21void

build()

28while (!q.empty())39}

40}41void

guess()

49for(int j=i;j<=n;j++)swap(a[i][j],a[t][j]);

50double s=a[i][i];

51for(int j=i;j<=n+1;j++)a[i][j]/=s;

52for(int j=i+1;j<=n;j++)56}

57for(int i=n;i;i--)63}

64}65int

main()

72build();

73 mi[0]=1;74

for(int i=1;i<=m;i++)mi[i]=mi[i-1]*2;75

for(int i=1;i<=n;i++)

82guess();

83for(int i=1;i<=n;i++)sum+=ans[i];

84for(int i=1;i<=n;i++)printf("

%.6f\n

",ans[i]/sum);

85 }

view code

luogu3706 SDOI2017 硬幣遊戲

link 硬幣遊戲 對於100分 我們不難想到這個矩陣過大 且沒有用的節點很多我們最後只要n個節點的答案 其他節點的答案可以不要。考慮把沒用的節點的答案壓到一點上。相同的套路 我們設f i 表示經過第i個點的期望次數 由於是到達某個點我們強制停止 所以概率 結果 期望次數。此時結果為1 0 所以這個...

luogu1146 硬幣翻轉

時空限制 1000ms 128mb 在桌面上有一排硬幣,共n枚,每一枚硬幣均為正面朝上。現在要把所有的硬幣翻轉成反面朝上,規則是每次可翻轉任意n 1枚硬幣 正面向上的被翻轉為反面向上,反之亦然 求乙個最短的操作序列 將每次翻轉n 1枚硬幣成為一次操作 輸入格式 輸入只有一行,包含乙個自然數n n為不...

luogu2708 硬幣翻轉

時空限制 1000ms 128mb 難度係數 如果你看懂了 從前有很多個硬幣擺在一行,有正面朝上的,也有背面朝上的。正面朝上的用1表示,背面朝上的用0表示。現在要求從這行的第乙個硬幣開始,將n個硬幣 1 n 硬幣個數 一起翻面,問如果要將所有硬幣翻到正面朝上,最少要進行這樣的操作多少次?輸入格式 乙...