Wannafly 11 挑戰賽F 白兔的遊戲

2021-08-28 14:19:45 字數 3175 閱讀 9250

nim遊戲是這樣的:有 n 個石子堆,第 i 個石子堆有 a[i] 個石子,兩個人輪流選擇乙個石子堆並從中拿走乙個或者多個石子。拿走最後乙個石子的人獲勝。

現在有兩個人他們決定每次隨機選擇乙個合法決策來操作。現在他們想知道在這種決策方式下先手的勝率以及所有可能的情況中先手獲勝的次數,對 998244353 取模。

即設答案化為最簡分式後的形式為 a/b ,其中 a 和 b 的互質。 輸出整數 x 使得 bx≡

amod

998244353

bx ≡ a ~mod ~998244353

bx≡amo

d998

2443

53且 0≤x

<

998244353

0 ≤ x < 998244353

0≤x<99

8244

353。 可以證明這樣的整數 x 是唯一的。

輸入描述:

第一行乙個正整數n,表示石子堆數。

第二行一共n個正整數a[i],表示每堆的石子數。

輸出描述:

一行兩個整數,分別表示先手的勝率和所有可能的情況中先手獲勝的次數,並對998244353取模。

1.考慮獲勝的概率,如果每個人都身不由己,即n堆石子都為1,則獲勝方是一定的,要麼一定贏要麼一定輸,否則55開。

2.根據博弈遊戲的性質,輸贏只和遊戲結束時的輪數有關,即先手奇數輪贏,偶數輪輸。

3.由隔板法,乙個大小為m

mm的堆,i

ii次操作取完的方案數是(m−

1i−1

)\binom

(i−1m−

1​) 。

4.考慮dp方程,設f[i

][j]

f[i][j]

f[i][j

] 為前i

ii堆j

jj次取完的方案數。考慮可重集合的排列數,則有轉移方程f[i

][j]

=∑k=

1a[i

]f[i

−1][

j−k]

(a[i

]−1k

−1)(

jk

)f[i][j] = \sum_^f[i-1][j-k] \binom \binom

f[i][j

]=k=

1∑a[

i]​f

[i−1

][j−

k](k

−1a[

i]−1

​)(k

j​)看起來有點像個卷積形式,把組合數拆開改寫一下就是

f [i

][j]

j!=∑

b+k=

jf[i

−1][

b](a

[i]−

1k−1

)1b!

1k

!\frac = \sum_ f[i-1][b] \binom \frac \frac

j!f[i]

[j]​

=b+k

=j∑​

f[i−

1][b

](k−

1a[i

]−1​

)b!1

​k!1

​ 再移一下項就是

f [i

][j]

j!=∑

b+k=

jf[i

−1][

b]b!

(a[i

−1]k

−1)1

k!

\frac = \sum_ \frac\binom \frac

j!f[i]

[j]​

=b+k

=j∑​

b!f[

i−1]

[b]​

(k−1

a[i−

1]​)

k!1​

喜聞樂見分治ntt

nttnt

t搞搞,然後發現之前的板子有個地方錯了

code:

#include

using namespace std;

typedef

long

long ll;

const

int maxn =

2e5+50;

const

int mod =

998244353

;const

int inv2 =

(mod +1)

>>1;

inline ll qpow

(ll a, ll b)

inline ll inv

(ll a, ll _mod)

ll fac[maxn]

, inv[maxn]

;void

init

(int n)

inline ll c

(int n,

int m)

struct ntt

}void

dft(vector

& a,

int flag)}}

if(flag ==-1

)}void

mul(vector

& a, vector

& b,

int m)

} ntt;

vector v[maxn]

;#define pii pair

#define fi first

#define se second

#define mp make_pair

priority_queue q;

intmain()

while

(q.size()

>1)

pii ret = q.

top();

ll ans =0;

for(

int i =

1;i.size()

;i+=2)

(ans +

= v[ret.se]

[i]* fac[i]

% mod)

%= mod;

int pp = inv2;if(

!flag) pp = n&1;

printf

("%d %lld\n"

,pp,ans)

;return0;

}

Wannafly挑戰賽14 F 細胞

題解 ntt 二項式定理 再逆fft求出係數ans i 本題即可解了 另 採用fft的話,複數既不方便,誤差也很大。從fft到ntt 由費馬小定理可知 gp 1 p 1 p為質數 所以利用這個性質來對應單位複數根乘方的週期性,即 includeusing namespace std typedef ...

Wannafly挑戰賽A 概率DP

給你乙個長 n 的序列,m 次查詢 每次查詢給乙個 x,然後 從序列的最左端 1 開始,每次隨機的選擇乙個右端點 r,如果兩個端點間的區間和不超過 x 就進行一次分割,然後把左端點變成 r 1,否則一直隨機下去。問這樣分割出來的期望段數 第一行兩個數 n,m 之後一行 n 個數表示這個序列 之後m行...

Wannafly挑戰賽5 補題

a 珂朵莉與宇宙 思路 科學暴力 列舉字首和,同時計算字首和裡面可能出現的完全平方數,匹配字首和 與完全平方數的差值是否在之前的字首和出現,出現了幾次就是存在多少個區間,利用的是連續的性質。include using namespace std typedef long long ll const ...