ZJOI2010 排列計數

2022-03-25 18:28:12 字數 1576 閱讀 9930

注意觀察題目:$pi>pi/2$。

發現特別像什麼?

二叉堆

於是就變成了:$n$個堆元素進行排列,滿足堆性質的排列對$p$的取模。(堆性質根據題意為大根堆)

設$f_i$為當前堆首為$i$的堆的排列方案數。為滿足堆性質$p_i$顯然只能取剩下若干數的最大值。

發現$f_i$影響$f_$和$f_$兩個結點。

以$i$為根的堆去掉根節點的結點數為$n-i$個,提前統計出第$i$個結點左子樹的大小$size_i$,則右邊為$n-i-size_i$個結點。

根據前面,可以得到這樣的轉移:$f_i=c(n-i,\ size)\times f_\times f_$。

解釋:從剩下的$n-i$個結點中選$size$個結點做其左子樹,然後對於每個子樹存在$f_$和$f_$中排列,根據乘法原理即得。

正確性:這些數是乙個排列,也就是說任意兩個數一定不相等,可以構成乙個嚴格遞增的序列。挑出的若干數及挑出若干數後仍能構成嚴格遞增的序列,所以可以化成子問題。

邊界:當前根結點為葉節點時,$f_i=1$。

最後答案:$f_1$。

注意:整個$dp$過程是$o(n)$的。但是存在計算組合數,複雜度為$o(n-i)$,$i$為當前根結點。根據遞迴主定理易知為$o(nlogn)$的複雜度。

存在模數,就要提前處理逆元。對於$p$過小還要用$lucas$定理,然而資料水而且我不會所以只寫了逆元。

1 #include 2

3using

namespace

std;45

#define re register

6#define rep(i, a, b) for (re int i = a; i <= b; ++i)

7#define repd(i, a, b) for (re int i = a; i >= b; --i)

8#define maxx(a, b) a = max(a, b);

9#define minn(a, b) a = min(a, b);

10#define ll long long

11#define inf (1 << 30)

1213 inline int

read()

1920

const

int maxn = 1e6 + 5;21

22int n, p, f[maxn << 1], g[maxn << 1

], inv[maxn];

2324

int c(int n, int

m) 30

31int dfs(int

u) 36

37int dp(int u, int

size)

4243

intmain()

53 dfs(1

);54 printf("

%d", dp(1

, n));

55return0;

56 }

ZJOI2010 排列計數

不是很懂為什麼洛谷上這題標籤有數字dp,於是我被騙來做這道題。不過上一道題也是一樣,其實也是組合數學。題意其實是求1.n1.n 1.n 的排列中有多少個可以構成小根堆。f i f i f i 表示以i ii為根的樹的方案數,l,r l,rl,r是左,右子樹結點個數,那麼有 f i f l f r c...

ZJOI2010 排列計數

求1 n的全排列 p i 的個數,滿足對於 i geq 2 有 p i p 隨手畫個圖就可以發現問題是求大小為 n 的小根堆的個數 由於左右子樹互不影響,直接dp即可,設 dp 表示以 i 為根的小根堆的個數,有 dp i dp dp c size i 1 size 注意本題模數可能小於 n 所以要...

ZJOI2010 排列計數

稱乙個1,2,n的排列p1,p2.pn是magic的,當且僅當2 i n時,pi pi 2.計算1,2,n的排列中有多少是magic的,答案可能很大,只能輸出模p以後的值 輸入檔案的第一行包含兩個整數 n和p,含義如上所述。輸出檔案中僅包含乙個整數,表示計算1,2,的排列中,magic排列的個數模 ...