我是靠谱客的博主 单薄豌豆,最近开发中收集的这篇文章主要介绍多项式学习笔记[三](全网最详细!有图有代码有解释有例题有总结!)多项式乘法的一些小Trick例题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 多项式乘法的一些小Trick
    • 关于差的“卷积”
    • 关于min/max的卷积
  • 例题
    • T1(Luogu P6300)
      • Description
      • Solution
    • T2(Luogu P3338)
      • Description
      • Solution
    • T3(Luogu P3321)
      • Description
      • Solution

多项式乘法的一些小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)

最后

以上就是单薄豌豆为你收集整理的多项式学习笔记[三](全网最详细!有图有代码有解释有例题有总结!)多项式乘法的一些小Trick例题的全部内容,希望文章能够帮你解决多项式学习笔记[三](全网最详细!有图有代码有解释有例题有总结!)多项式乘法的一些小Trick例题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部