前言.FFT \ NTT 算法

网上有很多,这里不再赘述。

模板见我的代码库:

FFT:戳我

NTT:戳我

正经向:FFT题目解题思路

\(FFT\)这个玩意不可能直接裸考的.....

其实一般\(FFT\)的题目难点不在于\(FFT\),而在于构造多项式与卷积。

两个经典例题:

[ZJOI2014]力

给定序列\(\{ q[1],q[2],....q[n]\}\)

定义:\(Ej = \sum_{i<j} \frac{q[i]}{(i-j)^2} - \sum_{i>j} \frac{q[i]}{(i-j)^2}\)

求\(E_1,E_2,E_3....E_{n-1},E_n\) , 数据范围:\(n\leq 10^5\)

.

[HNOI2017]礼物

给定两个节点带权的环,

\(<\ x_1,x_2,...x_n\ >\)与\(<\ y_1,y_2,...y_n\ >\),

现在你可以任意对齐,

对齐后,此时代价为\(\sum_{i=1}^n x_i y_j\) , 其中\(x_i\)与\(y_j\)对齐。

请求方案最小化此代价,数据范围\(n\leq 5\times 10^4\)

下文中,我们以 [HNOI2017]礼物 为主讲题, [ZJOI2014]对照训练。

下文中,为了方便描述,

我们用花括号表示 多项式系数元素 ,

如:\(f<x> = \{a_0,a_1,a_2,...,a_{n-1}\}\)

我们用中括号表示 多项式系数,

如:\(f(x)=a_0+a_1x+a_2x^2+.....+a_n x^n = [a_0,a_1,a_2,.....,a_n]\)

.

一般遇到这种构造多项式的题目,分三步走。

Step1 定元素

首先确定多项式系数元素是什么。

比如礼物这一题,我们假设第一个串的\(x_1\)对应第二个串的\(y_k\),那么:

\[Val = \sum_{i=1}^{n-k+1} x_i y_{i+k-1} \ + \ \sum_{i=1}^{k-1} x_{i+(n-k+1)} y_i \ ;
\]

显然前后两项分开考虑一下,下文中以分析\(\sum_{i=1}^{n-k+1} x_i y_{i+k-1}\)为例

我们要让\(\sum_{i=1}^{n-k+1} x_i y_{i+k-1}\)成为卷积的一个系数。

显然多项式的系数元素为:

\(f1 = \{ x_1,x_2,x_3.....x_n\}\) $\ \ \ \ \ \ \ \ \ \ $$f2 = { y_1,y_2,y_3.....y_n}$

[ZJOI2014]力 这题类似,可以得到:

\(f1 = \{ q[1],q[2],q[3].....q[n]\}\)

\(f2 = \{ \frac{1}{1^2},\frac{1}{2^2},\frac{1}{3^2}.....\frac{1}{(n+1)^2}\}\)

Step2 定顺序

显然多项式元素应该是单调递增或者单调递减排列的。

我们的第二步就是确定这个顺序。

考虑一下卷积系数的特性,

对于卷积的每一个系数,它的未知数次数来源为两个多项式。

所以如果我们想要把答案聚集在一个系数上,就应该保证对应元素未知数的次数和不变

那么只会有两种情况:

( 1 )形如\(\sum x_i y_{k-i}\) , 此时下标和不变,两个的顺序相同

( 2 )形如\(\sum x_i y_{k+i}\) , 此时下标差不变,两个的顺序相反

利用这个就可以确定我们构造的两个多项式系数排列顺序关系。

看[HNOI2017]礼物这题,\(\sum_{i=1}^{n-k+1} x_i y_{i+k-1}\)这个东西,

两个元素的下标差相同,所以两个多项式的系数顺序相反,即:

\(f1 = [ x_1,x_2,x_3.....x_n]\) $\ \ \ \ \ \ \ \ \ \ $$f2 = [y_n,y_{n-1},.....y_2,y_1]$

再看[ZJOI2014]力 :

我们以后面这一项为例:\(\sum_{i<j} \frac{q[i]}{(i-j)^2}\)

随着\(q[i]\)下标的增加,\(\frac{1}{(i-j)^2}\)下标减小 (\(i-j\)减小)。

所以 两者下标的和应该不变(或者手玩一把即可),即:

\(f1 = [q[1],q[2],q[3],....q[n]]\)

\(f2 = [\frac{1}{1^2},\frac{1}{2^2},\frac{1}{3^2}....\frac{1}{(n+1)^2}]\)

Step3 定答案

此时构造出来的卷积的某一项系数一定就是此时的对应答案。

关键是我们怎么确定这个答案。

这个其实并没有什么技巧,带特殊值手玩即可。

但是手玩的思路也要清晰,不然玩半天也玩不出来。

下面给一个比较清晰的思路:

.

[HNOI2017]礼物

这题的两个多项式:

\(f1 = x_1 a^0 +x_2 a^1+x_3 a^2.....x_n a^{n-1}\)

\(f2 = y_n a^0 + y_{n-1} a^1 ,.....y_2 a^{n-2} + y_1 a^{n-1}\)

考虑\(k = 1\)时,\(x_1\)与\(y_1\)对应,\(x_2\)与\(y_2\)对应.....

显然此时乘出来的未知数次数为\(n-1\)。

考虑\(k = 2\)时,\(x_1\)与\(y_2\)对应,\(x_2\)与\(y_3\)对应....

显然此时乘出来的未知数次数为\(n-2\)。

手玩出两个后就可以不玩了,因为答案肯定是连续的一段系数。

综上所述,当\(k=r\)时,答案系数 对应的未知数次数为 \(n-r\)。

.

定答案的时候,一定要注意答案是否有存在的意义

例如 [HNOI2017]礼物这题的另一项:$\sum_{i=1}^{k-1} x_{i+(n-k+1)} y_i \(
显然,当\)k = 1$的时候是没有任何意义的。

所以最后统计答案不能统计,从\(2\)开始\(for\)。

for(RG int i = 2; i <= N; i ++)ans[i] += (int)(f1[2*N-i].r+0.5);

注意细节,思路清晰,这一步也还是不难的。

[ZJOJ2014]力

\(f1 = q[1]a^0 + q[2]a^1 + q[3]a^2....q[n]a^{n-1}\)

\(f2 = \frac{1}{1^2}a^0 + \frac{1}{2^2}a^1 + \frac{1}{3^2}a^2 ....\frac{1}{(n+1)^2}a^{n-1}\)

\(\sum_{i<j} \frac{q[i]}{(i-j)^2}\)

当\(j = 1\)时,显然无意义舍去。

当\(j = 2\)时,\(res = \frac{q[1]}{\frac{1}{1^2}}\) , 未知数次数为 \(0\)

当\(j = 3\)时,$res = \frac{q[1]}{\frac{1}{2^2}} + \frac{q[2]}{\frac{1}{1^2}} $ , 未知数次数为 \(1\)

综上所述,当\(j = r(j \neq 1)\)时 ,对应的未知数次数为 \(r - 2\)。

附录: [HNOI 2017]礼物 的具体实现代码

#include<bits/stdc++.h>
#define IL inline
#define RG register
#define ll long long
#define _ 300005
using namespace std;
const double PI = acos(-1); int n,m,N,M,l, a[_] , b[_] ,Ans1,F1,F2,Ans, ans[_] , R[_];
struct Complex{
double r,i;
IL Complex(){ r = 0; i = 0; }
IL Complex(RG double a,RG double b){ r = a; i = b; }
IL Complex operator + (Complex B){return Complex(r+B.r,i+B.i);}
IL Complex operator - (Complex B){return Complex(r-B.r,i-B.i);}
IL Complex operator * (Complex B){
return Complex(r*B.r - i*B.i , r*B.i + i*B.r);
}
};
Complex f1[_] , f2[_] , X , Y; IL void FFT(RG Complex *P , RG int opt){
for(RG int i = 0; i < n; i ++)
if(i < R[i]) swap(P[i] , P[R[i]]);
for(RG int i = 1; i < n; i <<= 1){
RG Complex W(cos(PI/i),opt*sin(PI/i));
for(RG int j = 0 , p = i<<1; j < n; j += p){
RG Complex w(1,0);
for(RG int k = 0; k < i; k ++,w = w*W){
X = P[j+k]; Y = w*P[j+k+i];
P[j+k] = X+Y; P[j+k+i] = X-Y;
}
}
}
if(opt == -1)for(RG int i = 0; i < n; i ++)P[i].r /= n;
} IL void Solve(){
n = N - 1; m = 2*n; l = 0;
for(n = 1; n <= m; n<<=1) ++ l;
for(RG int i = 0; i <= N-1; i ++)
f1[i].r = a[i+1] , f2[i].r = b[N-i];
for(RG int i = 0; i < n; i ++)
R[i] = (R[i>>1]>>1) | ((i&1)<<(l-1));
FFT(f1,1); FFT(f2,1);
for(RG int i = 0; i < n; i ++)f1[i] = f1[i]*f2[i];
FFT(f1,-1);
for(RG int i = 1; i <= N; i ++)ans[i] = (int)(f1[N-i].r+0.5);
for(RG int i = 2; i <= N; i ++)ans[i] += (int)(f1[2*N-i].r+0.5);
Ans1 = 0;
for(RG int i = 1; i <= N; i ++)Ans1 = max(Ans1,ans[i]);
} int main(){
freopen("gift.in","r",stdin);
cin >> N >> M;
for(RG int i = 1; i <= N; i ++)cin >> a[i];
for(RG int j = 1; j <= N; j ++)cin >> b[j];
Solve();
for(RG int i = 1; i <= N; i ++)F1 += a[i]*a[i] + b[i]*b[i];
for(RG int i = 1; i <= N; i ++)F2 += a[i] - b[i];
Ans = 2147483640;
for(RG int c = -100; c <= 100; c ++)
Ans = min(Ans,F1+N*c*c+2*c*F2-2*Ans1);
cout<<Ans; return 0;
}

FFT \ NTT总结(多项式的构造方法)的更多相关文章

  1. [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)

    目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...

  2. FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ

    众所周知,tzc 在 2019 年(12 月 31 日)就第一次开始接触多项式相关算法,可到 2021 年(1 月 1 日)才开始写这篇 blog. 感觉自己开了个大坑( 多项式 多项式乘法 好吧这个 ...

  3. FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅲ

    第三波,走起~~ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅱ 单位根反演 今天打多校时 1002 被卡科技了 ...

  4. FFT&NTT&多项式相关

    打了FFT 感觉以后多项式不虚了 ~滑稽~ PS 关于详见没写完.... code #include<cmath> #include<cstdio> #include<c ...

  5. FFT/NTT/MTT学习笔记

    FFT/NTT/MTT Tags:数学 作业部落 评论地址 前言 这是网上的优秀博客 并不建议初学者看我的博客,因为我也不是很了解FFT的具体原理 一.概述 两个多项式相乘,不用\(N^2\),通过\ ...

  6. FFT&NTT总结

    FFT&NTT总结 一些概念 \(DFT:\)离散傅里叶变换\(\rightarrow O(n^2)\)计算多项式卷积 \(FFT:\)快速傅里叶变换\(\rightarrow O(nlogn ...

  7. 快速构造FFT/NTT

    @(学习笔记)[FFT, NTT] 问题概述 给出两个次数为\(n\)的多项式\(A\)和\(B\), 要求在\(O(n \log n)\)内求出它们的卷积, 即对于结果\(C\)的每一项, 都有\[ ...

  8. $FFT/NTT/FWT$题单&简要题解

    打算写一个多项式总结. 虽然自己菜得太真实了. 好像四级标题太小了,下次写博客的时候再考虑一下. 模板 \(FFT\)模板 #include <iostream> #include < ...

  9. FFT&NTT数学解释

    FFT和NTT真是噩梦呢 既然被FFT和NTT坑够了,坑一下其他的人也未尝不可呢 前置知识 多项式基础知识 矩阵基础知识(之后会一直用矩阵表达) FFT:复数基础知识 NTT:模运算基础知识 单位根介 ...

随机推荐

  1. SSE图像算法优化系列十六:经典USM锐化中的分支判断语句SSE实现的几种方法尝试。

    分支判断的语句一般来说是不太适合进行SSE优化的,因为他会破坏代码的并行性,但是也不是所有的都是这样的,在合适的场景中运用SSE还是能对分支预测进行一定的优化的,我们这里以某一个算法的部分代码为例进行 ...

  2. 阿里云学习之IOT物联网套件(配置篇)

    文档时间:2018.-1-24 首注:此文章是参照以下文章的整合与补充: https://bbs.aliyun.com/read/309106.html?amp;displayMode=1&p ...

  3. Ios App上传步骤

    前言:作为一名IOS开发者,把开发出来的App上传到App Store是必须的.下面就来详细介绍下具体流程. 1.打开苹果开发者中心:https://developer.apple.com 打开后点击 ...

  4. phpstudy如何安装景安ssl证书 window下apache服务器网站https访问

    1. 下载景安免费证书 https://www.zzidc.com/help/helpDetail?id=555 2.文件解压上传至服务器,位置自己决定 3. 调整apache配置 景安原文链接:ht ...

  5. Ansible playbook循环实践总结<一>

    1.标准Loops 标准loops可以直接减少task的次数,如下: [root@zero01 playbook]# vi loops.yaml --- - hosts: all gather_fac ...

  6. ubuntu16.04~qt 5.8无法输入中文

    编译fcitx-qt需要cmake,安装cmake命令,如果已经安装,请略过. sudo apt-get install cmake 安装 fcitx-libs-dev sudo apt-get in ...

  7. MysqL碎片整理优化

    先来说一下什么是碎片,怎么知道碎片有多大! 简单的说,删除数据必然会在数据文件中造成不连续的空白空间,而当插入数据时,这些空白空间则会被利用起来.于是造成了数据的存储位置不连续,以及物理存储顺序与理论 ...

  8. 基础--Redis在Linux环境下的安装

    1. 安装redis服务 1.1 检查安装依赖程序 yum install gcc-c++yum install -y tclyum install wget 1.1.1 下载redis安装包 (或者 ...

  9. session 与 coolie 的区别与联系

    cookie 和session 的区别: session 在服务器端,cookie 在客户端(浏览器) cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当 ...

  10. 用线性单元(LinearUnit)实现工资预测的Python3代码

    功能:通过样本进行训练,让线性单元自己找到(这就是所谓机器学习)工资计算的规律,然后用两组数据进行测试机器是否真的get到了其中的规律. 原文链接在文尾,文章中的代码为了演示起见,仅根据工作年限来预测 ...