浅谈小多项式快速幂
由模拟赛出了一个,完全不会
且GDKOI2021也出过,当时也是完全不会
可得半年来没有一点进步
Q
.
E
.
D
Q.E.D
Q.E.D
因为不会小多项快速幂被yyc D爆了
你怎么这么**菜!
故有了这篇文章
假设当前多项式为
F
(
x
)
F(x)
F(x)
F
(
x
)
k
+
1
=
F
(
x
)
k
F
(
x
)
F(x)^{k+1}=F(x)^{k}F(x)
F(x)k+1=F(x)kF(x)
分别求导
左边用复合函数求导,右边用乘法法则
(
k
+
1
)
F
(
x
)
k
F
′
(
x
)
=
(
F
(
x
)
k
)
′
F
(
x
)
+
F
(
x
)
k
F
′
(
x
)
(k+1)F(x)^kF'(x)=(F(x)^{k})'F(x)+F(x)^kF'(x)
(k+1)F(x)kF′(x)=(F(x)k)′F(x)+F(x)kF′(x)
k
F
(
x
)
k
F
′
(
x
)
=
(
F
(
x
)
k
)
′
F
(
x
)
\large kF(x)^kF'(x)=(F(x)^{k})'F(x)
kF(x)kF′(x)=(F(x)k)′F(x)
记住上面这条式子,后面可以推
k
∑
F
′
[
i
]
F
k
[
n
−
i
]
=
∑
F
[
i
]
(
n
−
i
+
1
)
F
k
[
n
−
i
+
1
]
k\sum F'[i]F^k[n-i]=\sum F[i](n-i+1)F^k[n-i+1]
k∑F′[i]Fk[n−i]=∑F[i](n−i+1)Fk[n−i+1]
把右边那块
i
=
0
i=0
i=0的分离出来,移项
F
[
0
]
(
n
+
1
)
F
k
[
n
+
1
]
=
k
∑
F
′
[
i
]
F
k
[
n
−
i
]
−
∑
i
=
1
F
[
i
]
(
n
−
i
+
1
)
F
k
[
n
−
i
+
1
]
F[0](n+1)F^k[n+1]=k\sum F'[i]F^k[n-i]-\sum\limits_{i=1} F[i](n-i+1)F^k[n-i+1]
F[0](n+1)Fk[n+1]=k∑F′[i]Fk[n−i]−i=1∑F[i](n−i+1)Fk[n−i+1]
这样就得到了一个关于
F
k
F^k
Fk的递推式
复杂度与
F
F
F的项数有关
假设多项式的非0系数有m个,要求0…n项
时间复杂度就是
O
(
n
m
)
O(nm)
O(nm)的
来道题康康
GDKOI Day 3 T2 ??? 好像是
B 二叉树
题目大意#
有个
n
n
n个叶子节点的二叉树,每个叶子节点的值为1,每个非叶子节点均有2个儿子。
有
k
k
k条信息,对于每个非叶子节点,如果其左儿子的叶子节点个数为
s
i
s_i
si,则其美观程度为
v
i
v_i
vi.
如果均不满足,则美观程度为
A
A
A
二叉树的美观程度为所有节点美观程度的乘积,求所有可能二叉树的美观程度之和
答案对
1000000007
1000000007
1000000007取模
题解#
设
f
[
n
]
f[n]
f[n]表示叶子节点个数为
n
n
n的答案,容易得出
f
[
1
]
=
1
f[1]=1
f[1]=1
f
[
n
]
=
∑
k
=
1
n
−
1
c
[
k
]
f
[
k
]
f
[
n
−
k
]
\large f[n]=\sum\limits_{k=1}^{n-1}c[k]f[k]f[n-k]
f[n]=k=1∑n−1c[k]f[k]f[n−k]
其中
c
[
s
i
]
=
v
i
c[s_i]=v_i
c[si]=vi,其他为
A
A
A
然而观察上面那个式子,发现
c
[
k
]
c[k]
c[k]是点乘上去的,不太方便写成卷积的形式,考虑把那些项挖掉
就是设
g
[
k
]
=
(
c
[
k
]
−
A
)
∗
f
[
k
]
g[k]=(c[k]-A)*f[k]
g[k]=(c[k]−A)∗f[k]
上面那个式子就可以写成
f
[
n
]
=
∑
k
=
1
n
−
1
f
[
k
]
f
[
n
−
k
]
+
∑
k
=
1
n
g
[
k
]
f
[
n
−
k
]
\large f[n]=\sum\limits_{k=1}^{n-1}f[k]f[n-k]+\sum\limits_{k=1}^{n}g[k]f[n-k]
f[n]=k=1∑n−1f[k]f[n−k]+k=1∑ng[k]f[n−k]
设
F
(
x
)
F(x)
F(x)为
f
n
{f_n}
fn的多项式,
G
(
x
)
为
g
的
G(x)为g的
G(x)为g的
可得
F
(
x
)
=
A
F
2
(
x
)
+
G
(
x
)
F
(
x
)
+
x
\large F(x)=AF^2(x)+G(x)F(x)+x
F(x)=AF2(x)+G(x)F(x)+x
最后那个
+
x
+x
+x表示加上只有一个点的方案数,准确来讲是
c
[
1
]
x
c[1]x
c[1]x,不过无所谓了
把每个
c
[
i
]
/
A
c[i]/A
c[i]/A变成
F
(
x
)
=
F
2
(
x
)
+
G
(
x
)
F
(
x
)
+
x
\large F(x)=F^2(x)+G(x)F(x)+x
F(x)=F2(x)+G(x)F(x)+x
解方程可得
F
(
x
)
=
1
−
G
(
x
)
−
(
1
−
G
(
x
)
)
2
−
4
x
2
\large F(x)=\frac{1-G(x)-\sqrt{(1-G(x))^2-4x}}{2}
F(x)=21−G(x)−(1−G(x))2−4x
然后直接套小多项式快速幂
开根就令
k
=
1
2
k=\frac{1}{2}
k=21
注意如果每次跟新
g
g
g后重新开根,时间复杂度不太对
可以带回上面解方程的那条式子求出根号里的那坨东西
code:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pi;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
typedef vector<pi> poly;
const int mod = 1000000007;
int add(int x, int y) { x += y;
if(x >= mod) x -= mod;
return x;
}
int sub(int x, int y) { x -= y;
if(x < 0) x += mod;
return x;
}
inline int mul(int x, int y) {
return 1ll * x * y % mod;
}
int qpow(int x, int y) {
int ret = 1;
for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
return ret;
}
const int N = 1000500;
int n, k, A, inv[N];
void init() {
inv[1] = 1;
for(int i = 2; i <= n; i ++)
inv[i] = mul(inv[mod % i], (mod - mod / i));
}
poly deriv(poly a) {
poly b;
for(int i = 0; i < a.size(); i ++) {
pi x = a[i];
if(x.fi) b.pb(mp(x.fi - 1, mul(x.se, x.fi)));
}
return b;
}
poly pf (poly a) {
poly c;
for(int i = 0; i < a.size(); i ++) {
pi x = a[i];
c.pb(mp(x.fi * 2, mul(x.se, x.se)));
for(int j = i + 1; j < a.size(); j ++) {
pi y = a[j];
c.pb(mp(x.fi + y.fi, mul(2 * x.se, y.se)));
}
}
return c;
}
poly getg2(poly g) {
g.pb(mp(0, mod - 1)); g = pf(g);
g.pb(mp(1, mul(mod - 4, 1)));
return g;
}
int sq[N], f[N];
poly Fd;
void calc(int n, poly F) {
int ret = 0;
for(int i = 0; i < Fd.size(); i ++) {
pi x = Fd[i];
if(0 <= x.fi && x.fi <= n) {
ret = add(ret, mul(x.se, sq[n - x.fi]));
}
}
ret = mul(ret, inv[2]);
for(int i = 0; i < F.size(); i ++) {
pi x = F[i];
if(1 <= x.fi && x.fi <= n) {
ret = sub(ret, mul(n - x.fi + 1, mul(x.se, sq[n - x.fi + 1])));
}
}
sq[n + 1] = mul(ret, inv[n + 1]);
f[n + 1] = mul(sq[n + 1], mod - inv[2]);
}
poly g, g2;
pi a[N];
int main(){
scanf("%d%d%d", &n, &k, &A); init();
for(int i = 1; i <= k; i ++) scanf("%d%d", &a[i].fi, &a[i].se), a[i].se = mul(a[i].se, qpow(A, mod - 2));
sort(a + 1, a + 1 + k);
g2 = getg2(g);
sq[0] = 1, sq[1] = mod - 2, f[1] = 1;
int j = 1;
for(int i = 1; i <= k; i ++) {
Fd = deriv(g2);
for(; j < a[i].fi; j ++) calc(j, g2);
g.pb(mp(a[i].fi, mul(f[a[i].fi], sub(a[i].se, 1))));
g2 = getg2(g);
for(int ii = 0; ii <= a[i].fi; ii ++) sq[ii] = mul(1, mul(f[ii], mod - 2));
for(int ii = 0; ii < g.size(); ii ++) {
pi x = g[ii];
sq[x.fi] = sub(sq[x.fi], x.se);
}
sq[0] = add(sq[0], 1);
}
Fd = deriv(g2);
for(; j < n; j ++) calc(j, g2);
printf("%d", mul(f[n], qpow(A, n - 1)));
return 0;
}
好像很NB的亚子
还是要多练习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!