UOJ424 集訓隊作業2018 count

2022-04-07 22:47:04 字數 2626 閱讀 2907

先特判掉 \(m>n\) 的情況。

考慮先確定乙個 \(f\) 陣列,然後判定他能否生成乙個好序列。

考慮先確定最靠左邊的最大值的位置,此時他大於等於後面的元素,然後嚴格大於前面的元素。

不難發現這種確定方式可以固定一組 \(f\) 序列,同時,如果這張圖上的最長鏈小於等於 \(m\),那麼這個答案就是合法的。

觀察到我們其實只關心長度,於是我們不難得到 \(\mathcal o(n^2m)\) 的暴力做法。

具體來說,令 \(f_\) 表示長度為 \(i\) 的序列,最大值為 \(j\) 的方案數,令 \(s_\) 為其字首和:

具體來說,我們發現這個實際上是乙個樹計數的過程,我們考慮一棵二叉樹,左兒子的邊為藍色,右兒子的邊為紅色,一棵樹合法當且僅當其不存在乙個點走到根節點需要經過 \(m\) 條藍邊。

這樣的話我們考慮直接對 \(s\) 序列進行計數,方便起見我們認為初始的答案為 \(1\),同時規定 \(s_=1\),不難發現:

邊界為 \(s_=s_=1\),答案為 \(s_\)

這個式子看上去就非常的卷積,我們從小到大列舉 \(j\),記 \(f_j(x)\) 表示其生成函式 \(\sum s_x^i\)

不難發現:\(f_j(x)=f_j(x)f_(x)x+1\) 於是得到 \(f_j(x)=\frac(x)x}\)

考慮一類函式復合,\(g(f(x))=\frac\),我們希望求得是 \(g(g(...g(\frac)))\)

基於觀察,我們發現答案一定可以寫成 \(\frac\)

這樣的話遞推形式即為 \(\fracx}=\frac\)

可以寫成矩陣的形式,通過矩陣快速冪 +ntt 處理即可,複雜度 \(\mathcal o(n\log^2 n)\)

最後還要多項式求逆一下。

有沒有更 easy 的做法呢?當然是有的!

注意到,這個題只需要我們算出其中一項 \(f_m[x^n]\),所以我們可以考慮一下奇怪的trick:

我們希望計算二叉樹的數量,可以考慮計算括號序列的數量,根據此題模型,我們可以考慮乙個這樣的轉換:

然後基於這樣的觀察我們發現任意的乙個括號序列都是合法的,將左括號設為 \(+1\),右括號設為 \(-1\) 問題等價於配對的括號序列使得不存在字首和大於 \(m\)(此時假設字首和為 \(x\) 等價於往 \(l\) 子樹走了 \(x-1\) 步)這樣的話我們給 \(m+1\),然後就是大於等於 \(m\) 了。

套路,不妨從座標系的角度考慮( \(y\) 表示左括號,\(x\) 表示右括號)我們等價於計算有多少條路徑,滿足不經過 \(y=x-1\) 和 \(y=x+m\),求走到 \((n,n)\) 的方案數。

這樣的話,仿照 [jloi2015]騙我呢 進行處理即可,複雜度 \(\mathcal o(n)\)

答案等於總方案數減去至少經過了 a,至少經過了 b,加上至少經過了 ab,至少經過了 ba,減去 ... 依次類推。

預處理組合數即可。

\(code:\)

#includeusing namespace std ;

#define next( i, x ) for( register int i = head[x]; i; i = e[i].next )

#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )

#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )

#define re register

#define int long long

int gi()

while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;

return cn * flus ;

}const int p = 998244353 ;

const int n = 2e5 + 5 ;

int n, m, ans, maxn, fac[n], inv[n] ;

struct node

} ed ;

int fpow(int x, int k) return ans ;

}int c(int x, int y)

int operator - (node a, node b)

node f(node x, int b)

int get(node x, int type)

signed main()

fac[0] = inv[0] = 1, ++ m ;

rep( i, 1, maxn )

fac[i] = fac[i - 1] * i % p, inv[i] = fpow(fac[i], p - 2) ;

ans = c(n + n, n) ; ed = node(n, n) ;

ans = ans - get(f(node(0, 0), -1), 0) ;

ans = ans - get(f(node(0, 0), m), 1) ;

ans %= p, ans = (ans + p) % p ;

cout << ans << endl ;

return 0 ;

}

UOJ424 集訓隊作業2018 count

將序列對應到笛卡爾樹,發現每棵笛卡爾樹只對應一種合法序列。因為在笛卡爾樹上往左走其對應的數至少減 1 往右走不一定減 1 所以這棵笛卡爾樹從根節點往左走的次數要 leqslant m 題目就轉化為了統計有多少棵 n 個節點的合法笛卡爾樹。笛卡爾樹是二叉樹,因為二叉樹和括號序列都可以用卡特蘭數計數,所...

UOJ449 集訓隊作業2018 喂鴿子

uoj 看題後 感覺自己越來越菜了,再這樣下去,要是正式考試送溫暖豈不是連溫暖都拿不到了。一臉min max反演的樣子,由於每個鴿子都等價,列舉子集大小 i ii 即可 a ns i 1n n i 1 i 1nif i ans sum n binom n i 1 frac n i f i ans i...

UOJ 449 集訓隊作業2018 喂鴿子

449.集訓隊作業2018 喂鴿子 dp好題 處理前m個,最快吃飽的鴿子期望的時間 根據期望的定義 考慮每個方案數的概率 期望次數 列舉前m個用了x個,概率都是 1 m x em x 而em x 表示往前m個扔了x個期望的總共次數,就是x n m 考慮用了x個的方案數 生成函式egf思想。而出現乙個...