OEIS首页的数列
无标号无根树计数
考虑用总的无标号有根树方案数减去根不是重心的方案数,这样每个方案只会在根为重心时被统计一遍
设点数为 n n n,已经求出 i i i个点的无标号有根树方案数为 f i f_i fi
n n n为奇数时
根据重心的性质,根节点不是重心,那么必然有一个子树大小 ≥ ⌈ n 2 ⌉ \ge \lceil \frac{n}{2} \rceil ≥⌈2n⌉
枚举这棵子树大小,答案等于 f n − ∑ k = ⌈ n 2 ⌉ n − 1 f k × f n − k f_n-\sum_{k=\lceil \frac{n}{2} \rceil}^{n-1}f_k\times f_{n-k} fn−∑k=⌈2n⌉n−1fk×fn−k
n n n为偶数时
可能同时存在两个重心,其中一个重心为根
断开两个重心之间的边,产生两棵以重心为根的树
若这两棵树完全相同,那么在 f f f中只会被统计一遍,不用减去
否则,这个方案在 f f f中会被统计两遍,需要减去一遍,总的方案数是 C f n 2 2 C_{f_{\frac{n}{2}}}^2 Cf2n2种
两棵子树大小不相等的情况,按照原来的方式计算即可
答案等于 f n − ∑ k = n 2 + 1 n − 1 f k × f n − k − C f n 2 2 f_n-\sum_{k=\frac{n}{2}+1}^{n-1}f_k\times f_{n-k}-C_{f_{\frac{n}{2}}}^{2} fn−∑k=2n+1n−1fk×fn−k−Cf2n2
无标号有根树计数
对于一个给定的根,这棵树的方案数相当于将除根外的所有点划分进若干棵不能为空的子树的方案数,那么构造方案数关于点数的 O G F OGF OGF,设为 F F F,那么有方程 F ( x ) = x × e u l e r ( F ( x ) ) F(x)=x\times euler(F(x)) F(x)=x×euler(F(x))
那么问题就是如何求解方程 F ( x ) − x × e u l e r ( F ( x ) ) = 0 F(x)-x\times euler(F(x))=0 F(x)−x×euler(F(x))=0
考虑倍增
直接倍增的做法
现在已经求出 f f f满足 f ( x ) − x × e u l e r ( f ( x ) ) ≡ 0 m o d x n f(x)-x\times euler(f(x))\equiv 0\mod x^n f(x)−x×euler(f(x))≡0modxn
考虑如何求出 F F F满足 F ( x ) − x × e u l e r ( F ( x ) ) ≡ 0 m o d x 2 n F(x)-x\times euler(F(x))\equiv 0\mod x^{2n} F(x)−x×euler(F(x))≡0modx2n
容易发现, ∀ k ≥ 2 \forall k\geq 2 ∀k≥2, f ( x k ) m o d x 2 n f(x^k)\mod x^{2n} f(xk)modx2n都可以很方便的求出,且 f ( x k ) ≡ F ( x k ) m o d x 2 n f(x^k)\equiv F(x^k)\mod x^{2n} f(xk)≡F(xk)modx2n
所以当 f f f为常数时, P ( x ) = x exp ∑ k = 2 f ( x k ) k m o d x 2 n P(x)=x\exp\sum_{k=2}\frac{f(x^k)}{k}\mod x^{2n} P(x)=xexp∑k=2kf(xk)modx2n也为常数
再带入 E u l e r Euler Euler变换的柿子,显然 F ( x ) − P ( x ) exp F ( x ) ≡ 0 m o d x 2 n F(x)-P(x)\exp F(x)\equiv 0\mod x^{2n} F(x)−P(x)expF(x)≡0modx2n
F ( x ) exp F ( x ) ≡ P ( x ) m o d x 2 n \frac{F(x)}{\exp F(x)}\equiv P(x)\mod x^{2n} expF(x)F(x)≡P(x)modx2n
再做牛顿迭代
现在已经求出 g g g满足 g ( x ) exp g ( x ) ≡ P ( x ) m o d x n \frac{g(x)}{\exp g(x)}\equiv P(x)\mod x^n expg(x)g(x)≡P(x)modxn
考虑如何求出 G G G满足 G ( x ) exp G ( x ) ≡ P ( x ) m o d x 2 n \frac{G(x)}{\exp G(x)}\equiv P(x)\mod x^{2n} expG(x)G(x)≡P(x)modx2n
求的是 H ( x ) = x exp x − P H(x)=\frac{x}{\exp x}-P H(x)=expxx−P, H ( F ( x ) ) ≡ 0 m o d x 2 n H(F(x))\equiv 0\mod x^{2n} H(F(x))≡0modx2n的 F F F
在 g ( x ) g(x) g(x)处将 H H H泰勒展开
H ( G ( x ) ) ≡ H ( g ( x ) ) + ∑ i = 1 H i ′ ( g ( x ) ) ( G ( x ) − g ( x ) ) i i ! m o d x 2 n H(G(x))\equiv H(g(x))+\sum_{i=1}\frac{H^{i'}(g(x))(G(x)-g(x))^i}{i!}\mod x^{2n} H(G(x))≡H(g(x))+i=1∑i!Hi′(g(x))(G(x)−g(x))imodx2n
≡ H ( g ( x ) ) + H ′ ( g ( x ) ) × ( G ( x ) − g ( x ) ) \equiv H(g(x))+H'(g(x))\times (G(x)-g(x)) ≡H(g(x))+H′(g(x))×(G(x)−g(x))
≡ 0 \equiv 0 ≡0
G ( x ) = g ( x ) − H ( g ( x ) ) H ′ ( g ( x ) ) G(x)=g(x)-\frac{H(g(x))}{H'(g(x))} G(x)=g(x)−H′(g(x))H(g(x))
考虑如何求 H ′ ( g ( x ) ) H'(g(x)) H′(g(x))
H ′ ( x ) = exp x − x exp x ( exp x ) 2 = 1 − x exp x H'(x)=\frac{\exp x-x\exp x}{(\exp x)^2}=\frac{1-x}{\exp x} H′(x)=(expx)2expx−xexpx=expx1−x
H ′ ( g ( x ) ) = 1 − g ( x ) exp g ( x ) H'(g(x))=\frac{1-g(x)}{\exp g(x)} H′(g(x))=expg(x)1−g(x)
(这里是对 g g g求导而不是 x x x)
G ( x ) = g ( x ) − g ( x ) exp g ( x ) − P ( x ) 1 − g ( x ) exp g ( x ) G(x)=g(x)-\frac{\frac{g(x)}{\exp g(x)}-P(x)}{\frac{1-g(x)}{\exp g(x)}} G(x)=g(x)−expg(x)1−g(x)expg(x)g(x)−P(x)
= g ( x ) + g ( x ) − P ( x ) × exp g ( x ) g ( x ) − 1 =g(x)+\frac{g(x)-P(x)\times \exp g(x)}{g(x)-1} =g(x)+g(x)−1g(x)−P(x)×expg(x)
该做法是正确的,复杂度也是正确的,但是常数巨大,只能过 50 % 50\% 50%的点, O ( n log n ) O(n\log n) O(nlogn)的复杂度 2 × 1 0 5 2\times 10^5 2×105跑了 25 s 25s 25s
代码
/*
void checker(long long * f,long long *P,int n)
{
static long long pd[800005],pdd[800005];
memset(pd,0,sizeof(pd));
memset(pdd,0,sizeof(pdd));
EXP(f,pd,n);
INV(pd,pdd,n);
MUL(f,pdd,pd,n,n);
printf("checker::f:");for(int i=0;i<n;i++)printf("%lld ",f[i]);printf("\n");
printf("checker::P:");for(int i=0;i<n;i++)printf("%lld ",P[i]);printf("\n");
printf("checker::frac{f}{exp f}-P:");for(int i=0;i<n;i++)printf("%lld ",pd[i]-P[i]);printf("\n");
}
*/
void Newton(long long * P,long long * G,int n)//答案存在G里
{
if(n==1)return G[0]=P[0],void();
static long long g[800005];
Newton(P,g,n>>1);
static long long Exp[800005];
EXP(g,Exp,n);
MUL(Exp,P,Exp,n,n);
for(int i=0;i<n;i++)Exp[i]=(g[i]-Exp[i]+p)%p;
static long long Inv[800005];
for(int i=0;i<n;i++)Inv[i]=0;
g[0]=(g[0]+p-1)%p;
INV(g,Inv,n);
g[0]=(g[0]+1)%p;
MUL(Exp,Inv,Exp,n,n);
for(int i=0;i<n;i++)
G[i]=(g[i]+Exp[i])%p;
}
long long inv[800005];
void Solve(long long * f,int n)//先要把n补成2的次幂
{
if(n==1)return f[0]=0,void();//\mod x意义下只要f\equiv 0即可
static long long g[800005];
Solve(g,n>>1);
static long long P[800005];
for(int i=0;i<n;i++)P[i]=0;
for(int k=2;k<n;k++)
for(int i=0;i*k<n;i++)
P[i*k]=(P[i*k]+g[i]*inv[k])%p;
static long long PP[800005];
EXP(P,PP,n);
for(int i=n-1;i>=1;i--)
PP[i]=PP[i-1];
PP[0]=0;
for(int i=0;i<n;i++)f[i]=0;
Newton(PP,f,n);
}
/*
200000
174218497
*/
基于直接倍增做法的大优化
参考题解,可以发现以上做法常数巨大的原因并不是因为需要做
exp
\exp
exp,而是倍增套倍增的层数太多了.
事实上,第一层倍增与第二层牛顿迭代完全可以合并.
回到一开始的问题.我们要求解的是方程 F ( x ) − x × e u l e r ( F ( x ) ) ≡ 0 m o d x n F(x)-x\times euler(F(x))\equiv 0\mod x^n F(x)−x×euler(F(x))≡0modxn
现在已经求得方程 f ( x ) − x × e u l e r ( f ( x ) ) ≡ 0 m o d x n / 2 f(x)-x\times euler(f(x))\equiv 0\mod x^{n/2} f(x)−x×euler(f(x))≡0modxn/2的解
显然, F ( x ) F(x) F(x)与 f ( x ) f(x) f(x)的前 n / 2 n/2 n/2项是相同的
将方程转化为 F ( x ) − P ( F ( x ) ) exp F ( x ) ≡ 0 m o d x n F(x)-P(F(x))\exp F(x)\equiv 0\mod x^n F(x)−P(F(x))expF(x)≡0modxn
其中 P ( F ( x ) ) ≡ x × exp ∑ k = 2 F ( x k ) k m o d x n P(F(x))\equiv x\times \exp\sum_{k=2}\frac{F(x^k)}{k}\mod x^n P(F(x))≡x×exp∑k=2kF(xk)modxn
显然, P ( F ( x ) ) = P ( f ( x ) ) P(F(x))=P(f(x)) P(F(x))=P(f(x))
牛顿迭代求解方程 F ( x ) − P ( F ( x ) ) exp F ( x ) ≡ 0 m o d x n F(x)-P(F(x))\exp F(x)\equiv 0\mod x^n F(x)−P(F(x))expF(x)≡0modxn
现在已经求得方程 g ( x ) − P ( F ( x ) ) exp g ( x ) ≡ 0 m o d x n / 2 g(x)-P(F(x))\exp g(x)\equiv 0\mod x^{n/2} g(x)−P(F(x))expg(x)≡0modxn/2
显然, g ( x ) − P ( f ( x ) ) exp g ( x ) ≡ 0 m o d x n / 2 g(x)-P(f(x))\exp g(x)\equiv 0\mod x^{n/2} g(x)−P(f(x))expg(x)≡0modxn/2,同时 f ( x ) − P ( f ( x ) ) exp f ( x ) ≡ 0 m o d x n / 2 f(x)-P(f(x))\exp f(x)\equiv 0\mod x^{n/2} f(x)−P(f(x))expf(x)≡0modxn/2
不难发现, g ( x ) ≡ f ( x ) m o d x n / 2 g(x)\equiv f(x)\mod x^{n/2} g(x)≡f(x)modxn/2
直接套用之前牛顿迭代的柿子
F
(
x
)
=
f
(
x
)
+
f
(
x
)
−
P
(
f
(
x
)
)
×
exp
f
(
x
)
f
(
x
)
−
1
F(x)=f(x)+\frac{f(x)-P(f(x))\times \exp f(x)}{f(x)-1}
F(x)=f(x)+f(x)−1f(x)−P(f(x))×expf(x)
该做法是正确的,复杂度也是正确的,但是常数也巨大,也只能过 50 % 50\% 50%的点,不过 O ( n log n ) O(n\log n) O(nlogn)的复杂度 2 × 1 0 5 2\times 10^5 2×105跑了 14 s 14s 14s,比之前快了不少
代码
void Solve(long long * f,int n)//先要把n补成2的次幂
{
if(n==1)return f[0]=0,void();//\mod x意义下只要f\equiv 0即可
static long long g[800005];
Solve(g,n>>1);
static long long P[800005];
for(int i=0;i<n;i++)P[i]=0;
for(int k=2;k<n;k++)
for(int i=0;i*k<n;i++)
P[i*k]=(P[i*k]+g[i]*inv[k])%p;
static long long PP[800005];
EXP(P,PP,n);
for(int i=n-1;i>=1;i--)
P[i]=PP[i-1];
P[0]=0;
static long long Exp[800005];
EXP(g,Exp,n);
static long long Inv[800005];
for(int i=0;i<n;i++)Inv[i]=0;
g[0]=(g[0]+p-1)%p;
INV(g,Inv,n);
g[0]=(g[0]+1)%p;
MUL(P,Exp,P,n,n);
for(int i=0;i<n;i++)
P[i]=(g[i]-P[i]+p)%p;
MUL(P,Inv,P,n,n);
for(int i=0;i<n;i++)
f[i]=(g[i]+P[i])%p;
}
基于两边取 ln \ln ln的做法
以上做法因为做了很多次 exp \exp exp,常数十分吓人.如果我们可以把 exp \exp exp换成 ln \ln ln,常数会优很多
回到一开始的问题.我们要求解的是方程 F ( x ) − x × e u l e r ( F ( x ) ) ≡ 0 m o d x n F(x)-x\times euler(F(x))\equiv 0\mod x^n F(x)−x×euler(F(x))≡0modxn
现在已经求得方程 f ( x ) − x × e u l e r ( f ( x ) ) ≡ 0 m o d x n / 2 f(x)-x\times euler(f(x))\equiv 0\mod x^{n/2} f(x)−x×euler(f(x))≡0modxn/2的解
显然, F ( x ) F(x) F(x)与 f ( x ) f(x) f(x)的前 n / 2 n/2 n/2项是相同的
将方程转化为 F ( x ) ≡ P ( F ( x ) ) exp F ( x ) m o d x n F(x)\equiv P(F(x))\exp F(x)\mod x^n F(x)≡P(F(x))expF(x)modxn
其中 P ( F ( x ) ) ≡ x × exp ∑ k = 2 F ( x k ) k m o d x n P(F(x))\equiv x\times \exp\sum_{k=2}\frac{F(x^k)}{k}\mod x^n P(F(x))≡x×exp∑k=2kF(xk)modxn
对这个柿子两边取
ln
\ln
ln
,
ln
F
(
x
)
≡
∑
k
=
2
F
(
x
k
)
k
+
ln
x
+
F
(
x
)
m
o
d
x
n
\ln F(x)\equiv \sum_{k=2}\frac{F(x^k)}{k}+\ln x+F(x)\mod x^{n}
lnF(x)≡∑k=2kF(xk)+lnx+F(x)modxn
显然, ln f ( x ) ≡ ∑ k = 2 F ( x k ) k + ln x + f ( x ) m o d x n / 2 \ln f(x)\equiv \sum_{k=2}\frac{F(x^k)}{k}+\ln x+f(x)\mod x^{n/2} lnf(x)≡∑k=2kF(xk)+lnx+f(x)modxn/2
设 P ( x ) = ∑ k = 2 F ( x k ) k + ln x P(x)=\sum_{k=2}\frac{F(x^k)}{k}+\ln x P(x)=∑k=2kF(xk)+lnx
设 G ( x ) = ln x − x − P G(x)=\ln x-x-P G(x)=lnx−x−P
G
′
(
x
)
=
1
x
−
1
G'(x)=\frac{1}{x}-1
G′(x)=x1−1
G
′
(
f
(
x
)
)
=
1
f
(
x
)
−
1
G'(f(x))=\frac{1}{f(x)}-1
G′(f(x))=f(x)1−1
F ( x ) = f ( x ) − ln f ( x ) − f ( x ) − P ( x ) 1 f ( x ) − 1 F(x)=f(x)-\frac{\ln f(x)-f(x)-P(x)}{\frac{1}{f(x)}-1} F(x)=f(x)−f(x)1−1lnf(x)−f(x)−P(x)
容易发现, f ( x ) f(x) f(x)的常数项为 0 0 0且一次方项不为 0 0 0,并不能求 ln \ln ln,同时 P ( x ) P(x) P(x)中的 ln x \ln x lnx也不能求出
那么,设 a ( x ) = f ( x ) x , A ( x ) = F ( x ) x a(x)=\frac{f(x)}{x},A(x)=\frac{F(x)}{x} a(x)=xf(x),A(x)=xF(x)
F
(
x
)
=
f
(
x
)
−
ln
a
(
x
)
+
ln
x
−
f
(
x
)
−
∑
k
=
2
f
(
x
k
)
k
−
ln
x
1
f
(
x
)
−
1
F(x)=f(x)-\frac{\ln a(x)+\ln x-f(x)-\sum_{k=2}\frac{f(x^k)}{k}-\ln x}{\frac{1}{f(x)}-1}
F(x)=f(x)−f(x)1−1lna(x)+lnx−f(x)−∑k=2kf(xk)−lnx
=
f
(
x
)
−
ln
a
(
x
)
−
∑
k
=
1
f
(
x
k
)
k
1
f
(
x
)
−
1
=f(x)-\frac{\ln a(x)-\sum_{k=1}\frac{f(x^k)}{k}}{\frac{1}{f(x)}-1}
=f(x)−f(x)1−1lna(x)−∑k=1kf(xk)
F ( x ) = f ( x ) + ln a ( x ) − ∑ k = 1 f ( x k ) k f ( x ) − 1 × f ( x ) F(x)=f(x)+\frac{\ln a(x)-\sum_{k=1}\frac{f(x^k)}{k}}{f(x)-1}\times f(x) F(x)=f(x)+f(x)−1lna(x)−∑k=1kf(xk)×f(x)
A ( x ) = a ( x ) − ln a ( x ) − ∑ k = 1 f ( x k ) k 1 a ( x ) − x A(x)=a(x)-\frac{\ln a(x)-\sum_{k=1}\frac{f(x^k)}{k}}{\frac{1}{a(x)}-x} A(x)=a(x)−a(x)1−xlna(x)−∑k=1kf(xk)
这样就不用求 exp \exp exp了
void Solve(long long * f,int n)//先要把n补成2的次幂
{
if(n==1)return f[0]=1,void();
static long long g[1600005];
Solve(g,n>>1);
static long long P[1600005];
for(int i=0;i<n;i++)P[i]=0;
for(int k=1;k<n;k++)
for(int i=1;i*k<n;i++)
P[i*k]=(P[i*k]+g[i-1]*inv[k])%p;
static long long Ln[1600005];
LN(g,Ln,n);
for(int i=0;i<n;i++)Ln[i]=(Ln[i]-P[i]+p)%p;
static long long Inv[1600005],IInv[1600005];
for(int i=0;i<n;i++)Inv[i]=0;
for(int i=0;i<n;i++)IInv[i]=0;
INV(g,Inv,n);
Inv[1]=(Inv[1]-1+p)%p;
INV(Inv,IInv,n);
MUL(Ln,IInv,Ln,n,n);
for(int i=0;i<n;i++)
f[i]=(g[i]-Ln[i]+p)%p;
}
long long f[1600005];
int main()
{
int n;
read(n);
for(int i=1;i<=1600000;i++)inv[i]=power(i);
int N=1;
while(N<n)N<<=1;
Solve(f,N);
for(int i=n;i>=1;i--)f[i]=f[i-1];
f[0]=0;
if(n&1)
{
long long ans=f[n];
for(int i=n/2+1;i<=n-1;i++)
ans=(ans+p-f[i]*f[n-i]%p)%p;
printf("%lld\n",ans);
}
else
{
long long ans=(f[n]-(f[n/2]-1)*f[n/2]/2%p+p)%p;
for(int i=n/2+1;i<=n-1;i++)
ans=(ans+p-f[i]*f[n-i]%p)%p;
printf("%lld\n",ans);
}
return 0;
}
未解之谜
- 按照柿子 F ( x ) = f ( x ) + ln f ( x ) x − ∑ k = 1 f ( x k ) k f ( x ) − 1 × f ( x ) F(x)=f(x)+\frac{\ln \frac{f(x)}{x}-\sum_{k=1}\frac{f(x^k)}{k}}{f(x)-1}\times f(x) F(x)=f(x)+f(x)−1lnxf(x)−∑k=1kf(xk)×f(x)牛顿迭代没法过,但是按照柿子 A ( x ) = a ( x ) − ln a ( x ) − ∑ k = 1 f ( x k ) k 1 a ( x ) − x A(x)=a(x)-\frac{\ln a(x)-\sum_{k=1}\frac{f(x^k)}{k}}{\frac{1}{a(x)}-x} A(x)=a(x)−a(x)1−xlna(x)−∑k=1kf(xk)牛顿迭代可以过,非常奇怪
- n n n最大会等于 2 18 2^{18} 218,但是把数组开到 8 × 1 0 5 8\times 10^5 8×105没法过,开到 16 × 1 0 5 16\times 10^5 16×105能过