多项式学习笔记[三](全网最详细!有图有代码有解释有例题有总结!)

多项式乘法的一些小Trick

关于差的“卷积”

众所周知,FFT/NTT 能够快速求出下面的数组 c c c

c i = ∑ j = 0 i a j b i − j c_i=\sum_{j=0}^i a_j b_{i-j} ci=j=0iajbij

但是,有的时候,我们要求的却是

c i = ∑ j = 0 n − i a j b i + j c_i=\sum_{j=0}^{n-i} a_j b_{i+j} ci=j=0niajbi+j

这显然不是卷积形式了。不慌,我们考虑将 a a a给翻转一下,即

c i = ∑ j = 0 n − i a n + 1 − j b i + j c_i=\sum_{j=0}^{n-i} a_{n+1-j} b_{i+j} ci=j=0nian+1jbi+j

由于 ( n + 1 ) − j + ( i + j ) = n + i + 1 (n+1)-j+(i+j)=n+i+1 (n+1)j+(i+j)=n+i+1 j j j无关,所以我们只需要将翻转后的 a a a b b b求一遍卷积得到 d d d,那么 c i = d n + 1 + i c_i=d_{n+1+i} ci=dn+1+i

关于min/max的卷积

此时我们要求的是 ∑ i = 0 n m i n ( a i , b n − i ) \sum_{i=0}^n min(a_i,b_{n-i}) i=0nmin(ai,bni)(以 m i n min min为例)。

这个式子不能直接用FFT/NTT去求。由于自然数 p p p满足 p = ∑ i = 1 ∞ [ i ≤ p ] p=\sum_{i=1}^{∞} [i \le p] p=i=1[ip],从而原式可以化为

∑ j = 1 ∞ ∑ i = 0 n [ j ≤ m i n ( a i , b n − i ) ] \sum_{j=1}^{∞} \sum_{i=0}^n [j \le min(a_i,b_{n-i})] j=1i=0n[jmin(ai,bni)]

∑ j = 1 ∞ ∑ i = 0 n [ j ≤ a i ] [ j ≤ b n − i ] \sum_{j=1}^{∞} \sum_{i=0}^n [j \le a_i] [j \le b_{n-i}] j=1i=0n[jai][jbni]

于是我们枚举 j j j,然后令 f i = [ j ≤ a i ] , g i = [ j ≤ b i ] f_i=[j \le a_i],g_i=[j \le b_i] fi=[jai],gi=[jbi]再累加 f , g f,g f,g的卷积即可。

关于这个东西的应用我们马上就会提到。

例题

T1(Luogu P6300)

Description

给定一个长度为 n n n的序列 A A A和一个数 m m m。对于每个在 [ 1 , m ] [1,m] [1,m]中的数 i i i,你需要分别回答:

⌊ \lfloor A A A序列中的数两两匹配(可能会有数不在任何匹配中),满足一个匹配中两个数的恰好等于 i i i的匹配的数量最大值 ⌉ \rceil

n ≤ 1 0 5 ,   a i ≤ 1 0 5 n \le 10^5,\ a_i \le 10^5 n105, ai105 m = max ⁡ a i m=\max {a_i} m=maxai

Solution

a a a A A A序列的桶,即 a i = ∑ j = 1 n [ A j = i ] a_i=\sum_{j=1}^n [A_j=i] ai=j=1n[Aj=i]

不难发现,一次询问的答案即为 ∑ j = 0 n m i n ( a j , b i − j ) \sum_{j=0}^n min(a_j,b_{i-j}) j=0nmin(aj,bij)。这个东西我们在上面提到过,可以先枚举 j j j,然后令 f i = [ j ≤ a i ] , g i = [ j ≤ b i ] f_i=[j \le a_i],g_i=[j \le b_i] fi=[jai],gi=[jbi]再累加 f , g f,g f,g的卷积得到 a n s ans ans数组。

但是这么做的时间复杂度是 O ( m 2 log ⁡ m ) O(m^2 \log m) O(m2logm)


同时,我们再去考虑一个暴力做法。

我们枚举桶中的两个数 i , j i,j i,j,将 a n s i , j ans_{i,j} ansi,j加上 m i n ( a i , a j ) min(a_i,a_j) min(ai,aj)

但是这么做的时间复杂度是 O ( m 2 ) O(m^2) O(m2)的。


考虑结合上面两种做法。

p p p为使用上述两种做法的分界点
①根据 a n s = ∑ j = 1 ∞ ∑ i = 0 n [ j ≤ a i ] [ j ≤ b n − i ] ans=\sum_{j=1}^{∞} \sum_{i=0}^n [j \le a_i] [j \le b_{n-i}] ans=j=1i=0n[jai][jbni],我们只将 j j j 1 1 1枚举到 p p p,剩下的 j j j我们暂不考虑
②对于所有满足比 p p p大的 a i a_i ai去暴力枚举累加贡献。

①的时间复杂度为 O ( p m log ⁡ m ) O(pm \log m) O(pmlogm),②的时间复杂度为 O ( ( n p ) 2 ) O((\frac n p)^2) O((pn)2)。为什么②的时间复杂度是 O ( ( n p ) 2 ) O((\frac n p)^2) O((pn)2)呢?因为这里的 a a a是一个,若 a i a_i ai p p p大,那么对应的,序列中 i i i出现的次数超过了 p p p。而序列中一共只有 n n n个数,所以满足比 p p p大的 a i a_i ai的级别只有 O ( n p ) O(\frac n p) O(pn)

于是总时间复杂度为 O ( p m log ⁡ m + ( n p ) 2 ) O(p m \log m+(\frac n p)^2) O(pmlogm+(pn)2)。令 m m m n n n同阶,解方程

p n log ⁡ n = ( n p ) 2 p n \log n=(\frac n p)^2 pnlogn=(pn)2

解得 p = n log ⁡ n p=\sqrt {\frac n {\log n}} p=lognn

而由于卷积的复杂度较大,我们取 p = n log ⁡ n 2 p=\frac {\sqrt {\frac n {\log n}}} 2 p=2lognn 实现是相对最优。

于是时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)

T2(Luogu P3338)

Description

在这里插入图片描述

Solution

a i = q i , b i = ( 1 i ) 2 a_i=q_i,b_i=(\frac 1 i)^2 ai=qi,bi=(i1)2,则有
E j = ∑ i = 1 j − 1 q i b j − i − ∑ i = j + 1 n q i b i − j E_j=\sum_{i=1}^{j-1} q_ib_{j-i}-\sum_{i=j+1}^{n} q_i b_{i-j} Ej=i=1j1qibjii=j+1nqibij

对于右式的前半部分,显然是一个关于“和”的卷积,直接NTT即可;而后半部分是一个关于“差”的卷积,按照本文开头所述的方法,我们需要翻转之后再求一遍卷积。

时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)。注意精度控制

T3(Luogu P3321)

Description

在这里插入图片描述

Solution

由于FFT只能处理关于“和”的卷积,所以我们先考虑化加为乘,这样会对问题起到极大的简化作用。

令在模意义下的底数为 b a s e base base。于是,我们就可以将问题转化为: 将给定的序列中的每一个数 a i a_i ai变成模意义下的 b a s e a i base^{a_i} baseai,请问能够生成多少个序列,使得这个序列各项之在模意义下为 log ⁡ b a s e x \log_{base} x logbasex

现在的问题就十分简单了:处理出原序列的桶,令桶为多项式的各项系数;我们做 ∣ S ∣ |S| S循环卷积,答案即为 x X x^{X} xX( x x x是形式幂级数, X X X为给定的值)项的系数。

我们直接多项式快速幂即可。本题得到完美解决!

正当你代码写完之后,发现……


b a s e base base取得不好的时候会出现像哈希冲突一样的玩意儿。比如 m o d = 6 , b a s e = 2 mod=6,base=2 mod=6,base=2时, 2 3 ≡ 2 1 ( m o d   6 ) 2^3 \equiv 2^1(mod\ 6) 2321(mod 6);也就是说, 2 2 2既可以表示为 2 2 2也可以表示为 4 4 4,这样导致了答案的不正确。

于是,你得出了以下结论——

⌊ \lfloor 这个 b a s e base base需要满足 b a s e 1 ⋯ b a s e m o d − 1 base^1 \cdots base^{mod-1} base1basemod1互不相同,也就是说真数 [ 1 , 2 ⋯ m o d − 1 ] [1,2 \cdots mod-1] [1,2mod1]与底数 [ 1 , 2 ⋯ m o d − 1 ] [1,2 \cdots mod-1] [1,2mod1]需一一对应。 ⌉ \rceil

这时恍然大悟的你发现了, b a s e base base事实上就是 m o d mod mod的原根。

于是我们套用原根的板子得到 b a s e base base,然后在模意义下转化数组与限制并多项式快速幂即可。

总时间复杂度为 O ( n + m log ⁡ m ) O(n+m \log m) O(n+mlogm)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值