【BZOJ3625】【CF438E】小朋友和二叉樹 NTT 生成函式 多項式開根 多項式求逆
題目大意
考慮一個含有
給出一個整數
我們只需要知道答案關於
題解
設
設
設
那麼
顯然,當常數項有逆元的時候一個多項式才有逆元。而
直接多項式開根+多項式求逆。
時間複雜度:
程式碼
#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("
相關推薦
【BZOJ3625】【CF438E】小朋友和二叉樹 NTT 生成函式 多項式開根 多項式求逆
題目大意
考慮一個含有n個互異正整數的序列c1,c2,…,cn。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合{c1,c2,…,cn}中,我們的小朋友就會將其稱作神犇的。並且他認為,一棵帶點權的樹的權值,是其所有頂點權值的總和。
給出一個整數
【BZOJ3625】【CF438E】小朋友和二叉樹(生成函式,多項式求逆,多項式開根,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]}中,我們的小朋友就會將其稱作
【bzoj3625】【CF438E/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[
【BZOJ3625】【codeforces438E】小朋友和二叉樹 生成函數+多項式求逆+多項式開根
== 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