日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[bzoj3625][Codeforces Round #250]小朋友和二叉树 (生成函数)

發布時間:2023/12/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [bzoj3625][Codeforces Round #250]小朋友和二叉树 (生成函数) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

description

我們的小朋友很喜歡計算機科學,而且尤其喜歡二叉樹。
考慮一個含有n個互異正整數的序列c[1],c[2],…,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],…,c[n]}中,我們的小朋友就會將其稱作神犇的。并且他認為,一棵帶點權的樹的權值,是其所有頂點權值的總和。
給出一個整數m,你能對于任意的s(1<=s<=m)計算出權值為s的神犇二叉樹的個數嗎?請參照樣例以更好的理解什么樣的兩棵二叉樹會被視為不同的。
我們只需要知道答案關于998244353(7172^23+1,一個質數)取模后的值。
Input

第一行有2個整數 n,m(1<=n<=10^5; 1<=m<=10^5)。
第二行有n個用空格隔開的互異的整數 c[1],c[2],…,c[n](1<=c[i]<=10^5)。
Output

輸出m行,每行有一個整數。第i行應當含有權值恰為i的神犇二叉樹的總數。請輸出答案關于998244353(=7172^23+1,一個質數)取模后的結果。
Sample Input
樣例一:
2 3
1 2
樣例二:
3 10
9 4 3
樣例三:
5 10
13 10 6 4 15
Sample Output
樣例一:
1
3
9
樣例二:
0
0
1
1
0
2
4
2
6
15
樣例三:
0
0
0
1
0
1
0
2
0
5
Hint

對于第一個樣例,有9個權值恰好為3的神犇二叉樹:

Source
VFleaKing & pyx1997 感謝wyl8899提供中文翻譯

solution

取模俺就省略不寫了
f[i]f[i]f[i]:表示權值和為iii的本質不同的子樹個數
g[i]g[i]g[i]:表示子樹根節點是否屬于∣C∣|C|C
則可以通過枚舉左右兒子及自己本身的權值,列出最暴力簡單的狀態轉移方程
fi=∑j=0ig[j]∑k=0i?jfkfi?j?kf_i=\sum_{j=0}^ig[j]\sum_{k=0}^{i-j}f_kf_{i-j-k}fi?=j=0i?g[j]k=0i?j?fk?fi?j?k?
這無非是一個卷積再卷積的形式,于是就跟生成函數沾邊了
fff序列的生成函數為F(x)F(x)F(x)ggg序列的生成函數為G(x)G(x)G(x),則有
F=G×F2+1F=G\times F^2+1F=G×F2+1
加1是因為這個子樹可能是只有根節點的
F=G×F2+1?GF2?F+1=0?F=1±1?4G2G?F=1?1?4G2GF=G\times F^2+1\Leftrightarrow GF^2-F+1=0\Rightarrow F=\frac{1±\sqrt{1-4G}}{2G}\Rightarrow F=\frac{1-\sqrt{1-4G}}{2G}F=G×F2+1?GF2?F+1=0?F=2G1±1?4G???F=2G1?1?4G??
套上多項式開根與多項式求逆即可
是一道碼農題

code

#include <cstdio> #include <iostream> using namespace std; #define int long long #define mod 998244353 #define maxn 300005 int inv2; int r[maxn], c[maxn], v[maxn], ni[maxn]; int A[maxn], B[maxn], F[maxn], G[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }void NTT( int *h, int opt, int n ) {int len = 1, l = 0;while( len < n ) len <<= 1, l ++;for( int i = 0;i < len;i ++ )r[i] = ( r[i >> 1] >> 1 ) | ( ( i & 1 ) << ( l - 1 ) );for( int i = 0;i < len;i ++ ) if( i < r[i] ) swap( h[i], h[r[i]] );for( int i = 1;i < len;i <<= 1 ) {int omega = qkpow( opt == 1 ? 3 : mod / 3 + 1, ( mod - 1 ) / ( i << 1 ) );for( int j = 0;j < len;j += ( i << 1 ) )for( int k = 0, w = 1;k < i;k ++, w = w * omega % mod ) {int x = h[j + k], y = h[j + k + i] * w % mod;h[j + k] = ( x + y ) % mod;h[j + k + i] = ( x - y + mod ) % mod;}}if( opt == -1 ) {int inv = qkpow( len, mod - 2 );for( int i = 0;i < len;i ++ )h[i] = h[i] * inv % mod;} }void polyinv( int n, int *f, int *g ) {if( n == 1 ) { g[0] = qkpow( f[0], mod - 2 ); return; }polyinv( ( n + 1 ) >> 1, f, g );for( int i = 0;i < n;i ++ ) A[i] = f[i], B[i] = g[i];NTT( A, 1, n << 1 );NTT( B, 1, n << 1 );for( int i = 0;i < ( n << 1 );i ++ ) A[i] = A[i] * B[i] % mod * B[i] % mod;NTT( A, -1, n << 1 );for( int i = 0;i < n;i ++ )g[i] = ( g[i] + g[i] - A[i] + mod ) % mod;for( int i = 0;i < ( n << 1 );i ++ ) A[i] = B[i] = 0; }void polysqrt( int n, int *f, int *g ) {if( n == 1 ) { g[0] = 1; return; }polysqrt( ( n + 1 ) >> 1, f, g );for( int i = 0;i < n;i ++ ) F[i] = f[i];polyinv( n, g, G );NTT( F, 1, n << 1 );NTT( G, 1, n << 1 );for( int i = 0;i < ( n << 1 );i ++ ) G[i] = G[i] * F[i] % mod;NTT( G, -1, n << 1 );for( int i = 0;i < n;i ++ )g[i] = ( G[i] + g[i] ) % mod * inv2 % mod;for( int i = 0;i < ( n << 1 );i ++ ) F[i] = G[i] = 0; }signed main() {inv2 = qkpow( 2, mod - 2 );int n, m;scanf( "%lld %lld", &n, &m );for( int i = 1, x;i <= n;i ++ ) {scanf( "%lld", &x );c[x] ++;}int len = 1;while( len <= m ) len <<= 1;for( int i = 0;i < len;i ++ )c[i] = mod - ( c[i] << 2 );c[0] ++;polysqrt( len, c, v );v[0] = ( v[0] + 1 ) % mod;polyinv( len, v, ni );for( int i = 1;i <= m;i ++ )printf( "%lld\n", ( ni[i] << 1 ) % mod );return 0; }

總結

以上是生活随笔為你收集整理的[bzoj3625][Codeforces Round #250]小朋友和二叉树 (生成函数)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。