1. 程式人生 > >【BZOJ3625】【CF438E】小朋友和二叉樹 NTT 生成函式 多項式開根 多項式求逆

【BZOJ3625】【CF438E】小朋友和二叉樹 NTT 生成函式 多項式開根 多項式求逆

題目大意

  考慮一個含有n個互異正整數的序列c1,c2,,cn。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c1,c2,,cn}中,我們的小朋友就會將其稱作神犇的。並且他認為,一棵帶點權的樹的權值,是其所有頂點權值的總和。
  給出一個整數m,你能對於任意的s(1sm)計算出權值為s的神犇二叉樹的個數嗎?
  我們只需要知道答案關於998244353取模後的值。

  n,m100000

題解

  設aic中有沒有i這個權值。

  設fi為權值和為i的二叉樹個數。

f0fi=1=0jiajk=0ijfkfijk
  設
A(x)F(x)=i0ai
xi
=i0fixi

  那麼
F(x)A(x)F(x)2F(x)+1ΔF(x)=F(x)2A(x)+1=0=14A(x)=1±14A(x)2A(x)=21±14A(x)
  顯然,當常數項有逆元的時候一個多項式才有逆元。而a0=0,所以只能取加號。
F(x)=21+14A(x)
  直接多項式開根+多項式求逆。

  時間複雜度:O(nlogn)

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime> #include<utility> #include<cmath> #include<functional> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> pll; void sort(int &a,int &b) { if(a>b) swap(a,b); } void open
(const char *s) { #ifndef ONLINE_JUDGE char str[100]; sprintf(str,"%s.in",s); freopen(str,"r",stdin); sprintf(str,"%s.out",s); freopen(str,"w",stdout); #endif } int rd() { int s=0,c; while((c=getchar())<'0'||c>'9'); do { s=s*10+c-'0'; } while((c=getchar())>='0'&&c<='9'); return s; } int upmin(int &a,int b) { if(b<a) { a=b; return 1; } return 0; } int upmax(int &a,int b) { if(b>a) { a=b; return 1; } return 0; } const ll p=998244353; const ll g=3; ll fp(ll a,ll b) { ll s=1; while(b) { if(b&1) s=s*a%p; a=a*a%p; b>>=1; } return s; } const int maxn=600000; ll inv[maxn]; namespace ntt { ll w1[maxn]; ll w2[maxn]; int rev[maxn]; int n; void init(int m) { n=1; while(n<m) n<<=1; int i; for(i=2;i<=n;i<<=1) { w1[i]=fp(g,(p-1)/i); w2[i]=fp(w1[i],p-2); } rev[0]=0; for(i=1;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1)); } void ntt(int *a,int t) { int i,j,k; int u,v,w,wn; for(i=0;i<n;i++) if(rev[i]<i) swap(a[i],a[rev[i]]); for(i=2;i<=n;i<<=1) { wn=(t==1?w1[i]:w2[i]); for(j=0;j<n;j+=i) { w=1; for(k=j;k<j+i/2;k++) { u=a[k]; v=1ll*a[k+i/2]*w%p; a[k]=(u+v)%p; a[k+i/2]=(u-v)%p; w=1ll*w*wn%p; } } } if(t==-1) { u=fp(n,p-2); for(i=0;i<n;i++) a[i]=1ll*a[i]*u%p; } } int x[maxn]; int y[maxn]; int z[maxn]; void copy_clear(int *a,int *b,int m) { int i; for(i=0;i<m;i++) a[i]=b[i]; for(i=m;i<n;i++) a[i]=0; } void copy(int *a,int *b,int m) { int i; for(i=0;i<m;i++) a[i]=b[i]; } void inverse(int *a,int *b,int m) { if(m==1) { b[0]=fp(a[0],p-2); return; } inverse(a,b,m>>1); init(m<<1); copy_clear(x,a,m); copy_clear(y,b,m>>1); ntt(x,1); ntt(y,1); int i; for(i=0;i<n;i++) x[i]=y[i]*(2-1ll*x[i]*y[i]%p)%p; ntt(x,-1); copy(b,x,m); } int c[maxn],d[maxn]; void sqrt(int *a,int *b,int m) { if(m==1) { if(a[0]==1) b[0]=1; else if(a[0]==0) b[0]=0; else //我也不會 ; return; } sqrt(a,b,m>>1); // copy_clear(c,b,m>>1); int i; for(i=m;i<m<<1;i++) b[i]=0; inverse(b,d,m); init(m<<1); for(i=m;i<m<<1;i++) b[i]=d[i]=0; ll inv2=fp(2,p-2); copy_clear(x,a,m); ntt(x,1); ntt(d,1); for(i=0;i<n;i++) x[i]=1ll*x[i]*d[i]%p; ntt(x,-1); for(i=0;i<m;i++) b[i]=(1ll*(b[i]+x[i])%p*inv2)%p; } }; int a[maxn]; int b[maxn]; int main() { open("bzoj3625"); int n,m; int i; int x; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { scanf("%d",&x); a[x]=1; } int k=1; while(k<=m) k<<=1; for(i=0;i<k;i++) a[i]=-4ll*a[i]%p; a[0]=(a[0]+1)%p; ntt::sqrt(a,b,k); b[0]=(b[0]+1)%p; ntt::inverse(b,a,k); for(i=1;i<=m;i++) { a[i]=(a[i]*2ll%p+p)%p; printf("

相關推薦

BZOJ3625CF438E小朋友 NTT 生成函式 多項式 多項式

題目大意   考慮一個含有n個互異正整數的序列c1,c2,…,cn。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c1,c2,…,cn}中,我們的小朋友就會將其稱作神犇的。並且他認為,一棵帶點權的樹的權值,是其所有頂點權值的總和。   給出一個整數

BZOJ3625CF438E小朋友生成函式多項式多項式NTT

Description 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 考慮一個含有n個互異正整數的序列c[1],c[2],...,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],...,c[n]}中,我們的小朋友就會將其稱作神犇的。

BZOJ 3625 小朋友生成函式+FFT)

Description 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 考慮一個含有n個互異正整數的序列c[1],c[2],...,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],...,c[n]}中,我們的小朋友就會

BZOJ 3625: [Codeforces Round #250]小朋友 dp 生成函式 多項式

3625: [Codeforces Round #250]小朋友和二叉樹Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 743  Solved: 336[Submit][Status][Discuss]Description我們

[bzoj 3625][Codeforces Round #250]小朋友 NTT多項式+多項式

Description 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 考慮一個含有n個互異正整數的序列c[1],c[2],…,c[n]。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c[1],c[2],…,c[n]}中,我們的小朋友就會將其稱作

bzoj3625CF438E/round250E小朋友FFT/NTT多項式多項式

題目連結 題解:我們設f[i]表示權值為i的二叉樹的數目,g[i]為i這個值是否在C集合中出現。則很容易得到f[x]=∑xi−1g[i]∑x−ij=0f[j]f[x−i−j]f[x]=∑i−1xg[i]∑j=0x−if[j]f[x−i−j],且f[0]=1f[

BZOJ3625codeforces438E小朋友 生成函數+多項式+多項式

== reverse turn chang 一個 函數 span 化簡 amp 首先,我們構造一個函數$G(x)$,若存在$k∈C$,則$[x^k]G(x)=1$。 不妨設$F(x)$為最終答案的生成函數,則$[x^n]F(x)$即為權值為$n$的神犇二叉樹個數

CF438E小朋友 解題報告

【CF438E】小朋友和二叉樹 Description ​ 我們的小朋友很喜歡電腦科學,而且尤其喜歡二叉樹。 ​ 考慮一個含有\(n\)個互異正整數的序列\(c_1,c_2,\dots,c_n\)。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合\(\{c_1,c_2,\dots,c_n\}\)中,

[bzoj3625][Codeforces Round #250]小朋友

math init std isp 二叉樹 表示 scrip fine c中 [bzoj3625][Codeforces Round #250]小朋友和二叉樹

BZOJ3625 [Codeforces Round #250]小朋友

using name 技術分享 const ++ 二叉 amp inverse gpo BZOJ3625 http://www.lydsy.com/JudgeOnline/problem.php?id=3625 #include<cstdio>

BZOJ3625: 小朋友

傳送門 Sol 設 f x f_

[BZOJ3625][Codeforces Round #250][多項式][多項式]小朋友

模板題 題解 #include <cstdio> #include <iostream> #include <algorithm> #include <string> #include <cstrin

BZOJ3625: [Codeforces Round #250]小朋友(OGF+牛頓迭代)

傳送門 題解: 看到這種二叉樹的題第一反應就是類似卡特蘭數的遞推。或者另外一種直觀的想法是看成一個點和兩邊的二叉樹的拼接,注意這裡不帶標號。 那麼很簡單了,對於點和二叉樹分別構造OGF:g(x),f(x),那麼: f=gf2+1 解二次方程: f=2

[CF438E] 小朋友

Description 給定一個整數集合 \(c\),對於每個 \(i\in[1,m]\),求有多少種不同的帶點權的二叉樹使得這棵樹點權和為 \(i\) 並且頂點的點權全部在集合 \(c\) 中。\(m\leq 10^5\)。 Solution 設 \(f[i]\) 為點權為 \(i\) 的二叉樹的方案

bzoj3625:[Codeforces Round #250]小朋友

n-1 namespace git using clas register ++ lin algo bzoj傳送門 luogu 生成函數,多項式 首先考慮這個題最顯然的\(dp\)方程,設\(f(n)\)為根節點權值為\(n\)的二叉樹個數,\(g(n)\)為權值為\(n\

BZOJ 3625 [Codeforces Round #250]小朋友 多項式

題意:連結 方法:多項式開根 解析: 首先先搞出來C(x)->即C的生成函式。 然後推一下式子嘛 選或者不選,選的話是一個遞迴,不選是1。 設F(x)為權值的生成函式。 即F(x)=C(x)∗F2(x)+1 然後搞一下。

[多項式 模板題] BZOJ 3625 [Codeforces Round #250]小朋友

令A(x)=∑i∈Sxi 以及f(x)為答案的母函式 那麼f(x)=A(x)∗f2(x)+1A(x)∗f2(x)−f(x)+1=0f(x)=1±1−4A(x)−−−−−−−−√2A(x)=21±1−4A(x)−−−−−−−−√ 因為f(0)=1 必取 21

bzoj-3625 小朋友

題意: 給出一個大小為n的集合C; 對於i=1...m計算有多少二叉樹滿足每個節點的權值都在集合C中且所有結點權值和為i; 對998244353取模,左右兒子有別; 題解: 生成函式系列題解之三? 這題先對C搞個生成函式吧,令其為C(x); 而我們要求的是樹的計數的函式F

bzoj 3625 小朋友 多項式

常數大到飛起。 O(nlogn)的演算法在CF上跑了2000ms也是神奇。 有空看下怎麼常數寫小一點。。 NTT做了個小優化,快了一點 #include <iostream> #include <cstdio> #include <cs