FFT Part

公式

欧拉公式: \(e^{i\theta}=\cos{\theta}+i\sin{\theta}\)

特殊形式:\(e^{i\pi}=-1\)

Begin

一个多项式 \(F=x^2+x+1\)

简写作 \((1,1,1)\)

现在我们知道只需要三个点就可以唯一确定其图像 (玄学结论)

假如我们随意代数,则秦九条乱搞是 \(O(n^2)\)

DFT

于是我们设 \(w_n=e^{\frac{2i\pi}{n}}\)

代数 \(w_n^n=e^{2\pi i}=(e^{i\pi})^2=(-1)^2=1\)

我们代数的时候不带入 \(0,1,2,3,4,5...\)

而是带入 \(w_n^0,w_n^1,......\)

这就是 \(DFT\)

然而它仍然是暴力 \(N^2\) 复杂度

FFT

设一个多项式 \(A=x^7+2x^6+3x^5+4x^4+5x^3+6x^2+7x+8\)

则 拆开

\(A_1=x^6+3x^4+5x^2+7\)

\(A_2=2x^6+4x^4+6x^2+8\)

我们发现 \(A=xA_1+A_2\)

然后我们知道 \(FFT(A_1\ or\ A_2)\) 带入的其实是 \(w_4\)

但是他的 \(X\) 其实是 \(X^2\)

\(So\) \(w_4^i\) 其实对应实际上的 \(w_8^i\) 和 \(w_8^{i+4}\)

设 \(FFT(A,i)\) 是带入 \(w_{length(A)}^i\) 的结果

则 \(FFT(A,i)=FFT(A_2,i)+x FFT(A_1,i)=FFT(A_2,i)+w_{length(A)}^i FFT(A_1,i)\)

\(FFT(A,i+\frac{length(A)}2)=FFT(A_2,i)+x FFT(A_1,i)=FFT(A_2,i)+w_{length(A)}^{i+\frac{length(A)}2}FFT(A_1,i)=FFT(A_2,i)-w_{length(A)}^i FFT(A_1,i)\)

分治着去做就可以了

IFFT

直接将单位根变成 \(w'_n=e^{-\frac{2i\pi}{n}}\) 做 \(FFT\)

最后记得除以 \(length\)

具体过程别管了

你看不懂我也看不懂

实现

一般我们都写循环版本

至于二进制逆序之类,建议直接看板子

复数可手写可 \(STL\)

Code

P1919 A*B Problem

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const double pi=3.1415926535897932384626;
const int N=4000009;
typedef complex<db> com;
int rev[N];
void FFT(com *x,int len,db op){
for(int i=0;i<len;i++)if(i<rev[i])swap(x[i],x[rev[i]]);
for(int l=2;l<=len;l<<=1){
com rt(cos(2*pi/(db)l),op*sin(2*pi/(db)l));
for(int i=0;i<len;i+=l){
com w(1,0);
for(int r=i;r<=i+l/2-1;r++){
com u=x[r],v=w*x[r+l/2];
x[r]=u+v,x[r+l/2]=u-v;
w*=rt;
}
}
}
if(op<0)for(int i=0;i<len;i++)x[i]/=(db)len;
}
com k[N],k2[N];
char a[N],b[N];
int la,lb,ans[N];
int main(){
int len=1;
scanf("%s%s",a,b),la=strlen(a),lb=strlen(b);
for(int i=0;i<la;i++)k[i].real(a[la-i-1]-'0'),k[i].imag(0);
for(int i=0;i<lb;i++)k2[i].real(b[lb-i-1]-'0'),k2[i].imag(0);
while(len<la+lb-1)len<<=1;
for(int i=0;i<len;i++){
rev[i]=rev[i>>1]>>1;
if(i&1)rev[i]+=len>>1;
}
FFT(k,len,1.0),FFT(k2,len,1.0);
for(int i=0;i<len;i++)k[i]*=k2[i];
FFT(k,len,-1.0);
for(int i=0;i<la+lb-1;i++)ans[i]=(int)(k[i].real()+0.2);
for(int i=0;i<la+lb-2;i++)ans[i+1]+=ans[i]/10,ans[i]%=10;
for(int i=la+lb-2;i>=0;i--)printf("%d",ans[i]);
return 0;
}

例题

P3723 礼物

求 \(min \sum_{i=1}^n{(x_i-y_i+c)^2}\ \ (1<=n<=50000,-500<=c<=500)\)

Solution

直接展开

原式 \(=\sum{x_i^2+y_i^2+c^2+2x_ic-2y_ic-2x_iy_i}\)

\(=\sum{x_i^2}+\sum{y_i^2}+nc^2+2c\sum{x_i}-2c\sum{y_i}-2\sum{x_iy_i}\)

只需要最大化最后一项即可

\(c\) 怎么办呢?枚举!

\(\sum{x_iy_i}\) 看似无法处理

实则也确实无法处理

有个小 \(trick\) ,把 \(x\) 数组倒置过来

然后就变成了 \(\sum{x_{n-i+1}y_i}\)

看似还是白扯

但我们发现这样的项有一个性质

其下标相加为 \(n+1\) !

所以我们把每一个下标都当作次数

\(Fast\ Fast\ TLE\) 搞一搞就可以了

但我们想到一颗问题

就是旋转则么办?

我们设第一个手环的偏移量为 \(\theta\) 且 \(0<=\theta<=n-1\)

然后就变成了 \(\sum{x_{n-i+1+\theta}y_i}\)

求和为 \(n+1<=n+\theta+1<=2n\)

只需要找最大的系数即可

Code
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef complex<db> com;
const int N=300009;
const db pi=3.1415926535897932385626;
int rev[N],len;
ll asum,bsum,asq,bsq,ans=LONG_LONG_MAX;
void FFT(com *x,db op){
for(int i=0;i<len;i++)if(i<rev[i])swap(x[i],x[rev[i]]);
for(int l=2;l<=len;l<<=1){
com rt(cos(2.0*pi/(db)l),op*sin(2.0*pi/(db)l));
for(int i=0;i<len;i+=l){
com w(1,0);
for(int r=i;r<i+l/2;r++){
com u=x[r],v=w*x[r+l/2];
x[r]=u+v,x[r+l/2]=u-v;
w*=rt;
}
}
}
if(op<0)for(int i=0;i<len;i++)x[i]/=(db)len;
}
com a[N],b[N]; int main(){
int n,m,tmp;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%d",&tmp),a[n-1-i].real(tmp),a[n+n-1-i].real(tmp),asum+=tmp,asq+=tmp*tmp;
for(int j=0;j<n;j++)scanf("%d",&tmp),b[j].real(tmp),bsum+=tmp,bsq+=tmp*tmp;
len=1;
while(len<n+n+n-1)len<<=1;
for(int i=0;i<len;i++){
rev[i]=rev[i>>1]>>1;
if(i&1)rev[i]|=len>>1;
}
FFT(a,1.0),FFT(b,1.0);
for(int i=0;i<len;i++)a[i]*=b[i];
FFT(a,-1.0);
for(int i=n+1;i<=n+n;i++){
for(int c=-m;c<=m;c++){
//if(fabs(a[i].imag())>0.5)puts("Fuck!"),exit(0);
ans=min(ans,asq+bsq+n*c*c+2ll*asum*c-2ll*bsum*c-2ll*(ll)(a[i].real()+0.2));
}
}
printf("%lld",ans);
return 0;
}

NTT Part

Reason For NTT

\(FFT\) 算法有一个问题:有些题目需要进行取模,而 \(FFT\) 的 \(double\) 显然做不到

所以我们能不能找一个可以取模的算法呢

\(NTT\) 就是解决这个问题的

但有一个很严重的问题

就是 \(NTT\) 并非任意模数

一般用得较多的是质数 \(998244353\)

\(So\ Let's\ Begin\)

Start

欧拉定理 \(a^{\phi(k)}\equiv 1 \mod k\)

当 \(k\) 为质数时得 \(a^{p-1}\equiv 1 \mod p\) 就是著名的费马小定理

接下来我们引入原根的概念

质数 \(i\) 的原根记作 \(g_i\)

(本文仅叙述方便,不保证叙述严格)

这个是啥意思呢

就是 \(g_i\) 的所有幂次能取遍所有模 \(i\) 的余数

并且他是有周期性的

显然 \(g_i^0=g_i^{i-1}=1\)

可知周期 \(C=i-1\)

这就能解释一个疑问:为什么必须是 \(998244353\) 等几个有限的数

首先,这个模数必须是一个质数,要不他不满足费马小定理

然后,\(998244353=119×2^{23}+1\)

所以这个模数的好处就是他的周期是 \(q*2^k\)

NTT

还记得刚才讲的 \(FFT\) 吗?

我们是怎么做的?

我们知道他是表示成 \(A= xA_1+A_2\) 的形式

因为我们是分治的方法

所以我们代入得其实就是 \(2^k\) 个 \(Value\)

而且要保证他有周期性

平方之后对应上一层的 \(Value\)

我们上一次是用复数来实现的

但是其实原根也可以

我们想一下这个单位元是多少

首先我们定义 \(w_i\) 为一个周期为 \(i\) 的单位元

所以原来的朴素原根 \(g_i\) 周期为 \(q*2^k\) 即 \(P-1\)

如果想要缩短其周期那么必须进行乘方

所以我们容易得知 \(w_i=g^\frac{P-1}{i}\)

而显然 \(i\) 为 \(2^k\) 如果他的周期不能整除那肯定不行

然后就没有了

当然一般你的序列长度是会小于 \(2^{23}\) 即 \(8e6\) 的

所以这个模数基本上是够的

A Small Problem

现在只有一个问题:怎么求原根?

我才不会告诉你我也不知道

\(998244353,1004535809\) 的原根都是 \(3\)

实现细节

我们的单位根和 \(FFT\) 一模一样

所以 \(INTT\) 、 位逆序等等都都是一模一样的

所以 \(INTT\) 也需要乘 \(1/n\) ,单位元也需要变成逆元

Code [P1919]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4000009;
const ll Mod=998244353,Root=3;
int len=1,rev[N];
ll Pow(ll d,ll x){
ll ans=1,tmp=d;
while(x){
if(x&1)ans=(ans*tmp)%Mod;
tmp=(tmp*tmp)%Mod;
x>>=1;
}
return ans;
}
ll Inv(ll u){return (Pow(u,Mod-2)+Mod)%Mod;}
void NTT(ll *x,bool I){
for(int i=0;i<len;i++)if(i<rev[i])swap(x[i],x[rev[i]]);
for(int l=2;l<=len;l<<=1){
ll rt=Pow(Root,(Mod-1)/l);
if(I)rt=Inv(rt);
for(int i=0;i<len;i+=l){
ll w=1;
for(int j=i;j<=i+l/2-1;j++){
ll u=x[j],v=w*x[j+l/2]%Mod;
x[j]=(u+v)%Mod,x[j+l/2]=(u-v+Mod)%Mod;
w=(w*rt)%Mod;
}
}
}
ll Inv_n=Inv(len);
if(I)for(int i=0;i<len;i++)x[i]=(x[i]*Inv_n)%Mod;
}
ll a[N],b[N];
int main(){
int la=-1,lb=-1;
char k=getchar();
while(!isdigit(k))k=getchar();
while(isdigit(k))a[++la]=k-'0',k=getchar();
while(!isdigit(k))k=getchar();
while(isdigit(k))b[++lb]=k-'0',k=getchar();
for(int i=0;i<la-i;i++)swap(a[i],a[la-i]);
for(int i=0;i<lb-i;i++)swap(b[i],b[lb-i]);
while(len<la+lb+1)len<<=1;
for(int i=0;i<len;i++){
rev[i]=rev[i>>1]>>1;
if(i&1)rev[i]|=len>>1;
}
NTT(a,0),NTT(b,0);
for(int i=0;i<len;i++)a[i]=(a[i]*b[i])%Mod;
NTT(a,1);
for(int i=0;i<la+lb;i++)a[i+1]+=a[i]/10,a[i]%=10;
int i=la+lb;
while(i>0&&a[i]==0)--i;
for(;i>=0;i--)printf("%lld",a[i]);
return 0;
}

FWT Part

前言

本部分推荐配合 OI-WiKi 使用

并大量参考了其中内容

Reason For FWT

\(FFT\) 和 \(NTT\) 求多项式乘法已经很不错了

但我们写一下多项式乘法的一种形式

\[C[i]=\sum_{j+k=i}{A[j]*B[k]}
\]

其中 \(C\) 是答案数组

\(A,B,C[i]\) 表示的是这个多项式次数为 \(i\) 的项的系数

而有的时候毒瘤题目要求的是下面的式子

\[C[i]=\sum_{j\oplus k=i}{A[j]*B[k]}
\]

其中的 \(\oplus\) 可能是与,或,异或。

这个东西 \(FWT\) 可以搞

Start

我们的整体思路仍然是转换 \(A\) \(B\) 数组的形式

让它变成一种奇怪的表示方法

然后可以 \(O(n)\) 计算

然后再转换回去

记住这个思路,后面会用

同时, \(FWT\) 和我们前两个算法的差异还是很大的,勿硬套

\(FWT\) 算法有一个答案 \(C\) 数组和三个 \(FWT\) 数组(ABC 各开一个)(可以直接用各自的数组,不需要真的开出来)

下文写作 \(FAT\) \(FBT\) \(FCT\)

如对三个数组都满足则写作 \(FWT\)

如果指的是 \(ABC\) 则写作 \(W\)

\(OK,Let's\ Go!\)

OR

现在我们要干什么?

求 \(C\) 数组。

\(C\) 数组满足什么?

\(C_i=\sum_{i=j|k}{A_jB_k}\) 。

那么我们的 \(FWT\) 是干什么的?

沃尔什大佬定义了 \(FWT\) 的定义和计算方式

即 \(FAT_i*FBT_i=FCT_i\)

而想要保证 \(FWT_i=\sum_{j|i=i}{W_j}\)

注意 \(FWT\) 数组和 \(W\) 数组不一样!

我们发现当 \(FAT\) \(FBT\) 都满足性质的时候 \(FCT\) 同样满足性质

抄一个 OI-Wiki 上的公式

\[\begin{aligned}
FAT_i\cdot FBT_i&=\left(\sum_{i|j=i} A_j\right)\left(\sum_{i|k=i} B_k\right) \\
&=\sum_{i|j=i}\sum_{i|k=i}A_jB_k \\
&=\sum_{i|(j|k)=i}A_jB_k \\
&= FCT_i
\end{aligned}
\]

最后两步好好看看

对照一下 \(C_i\) 和 \(FWT_i\) 的公式

\(You\ Will\ Get\ It.\)

那么我们接下来看怎么求一段区间的 \(FWT\)

暴力不用想, \(O(n^2)\)

显然如果只有一个数的区间 \(FWT\) 直接 \(CV\) 原数据即可

显然如果只有一个数的区间 \(FWT\) 直接 \(CV\) 原数据即可,不多赘述

根据我们某某T的学习经验,我们一定是要分治实现 \(n\log n\) 的

\(FWT\) 的根本思想是:

既然你的操作都是基于二进制的

那我就用二分把每个下标的二进制位拆出来!

我们令 \(Q\) 表示当前\(FWT\)区间的前一半,\(H\) 表示区间的后一半。(Qian Hou qwq)

显然,如果你从 \(0\) 开始算下标的话

\(Q\) 的下标二进制最高位都是 \(0\)

\(H\) 的下标二进制最高位都是 \(1\)

注:知道各位 dalao 在想什么,这里其实说法不严谨,比如说我们现在的一段区间 \([2,3]\) ,二进制表示是 \(10\) 和 \(11\),他的前面是可能有一个相同的前缀的。但联系当时我们 \(FFT\) 的算法,这里我们不把区间当成原序列的一部分,而是把他们当成完整的我们想求的区间 而我们已经知道了他们左右区间“单独” \(FWT\) 的值,然后我们只需要将他们合并即可,此处亦可将其定义成“去掉前缀后的下标二进制最高位”。

我们发现,合并后的 \(FWT\) 数组,\(Q\) 部分不会受到后面影响(因为 \(H\) 部分所有的下标上都会有一个额外的 \(1\))

但 \(H\) 数组却需要加上 \(Q\) 数组

因为这是 \(OR\) !

你问咋加? 语法入门循环结构,直接加!

至于求逆,由于他的数组是 \(H\) \(H+Q\)

所以直接 \(Q-=H\) 即可

放个详细注释版的 \(Oi-Wiki\) 代码

void Or(ll *a, ll type) {  // 迭代实现,常数更小
for (ll x = 2; x <= n; x <<= 1) {//区间长度
ll k = x >> 1;
for (ll i = 0; i < n; i += x) {//枚举区间左端点
for (ll j = 0; j < k; j++) {//枚举 H 中的每个点
(a[i + j + k] += a[i + j] * type) %= P;
//type 为 1 时是 FWT,-1 是 IFWT
}
}
}
}

是不是很简单?好了我们继续!

AND

Wiki 此部分未给出证明

但我们还是要简单搞一下的

根据常识,沃尔什大佬不会轻易改基础定义

所以我们把基础公式搞过来

\[FAT_i*FBT_i=FCT_i
\]
\[FWT_i=\sum_{j\&i=i}{W_j}
\]
\[C_i=\sum_{i=j\&k}{A_jB_k}
\]

再搞一个证明公式

\[\begin{aligned}
FAT_i\cdot FBT_i&=\left(\sum_{i\&j=i} A_j\right)\left(\sum_{i\&k=i} B_k\right) \\
&=\sum_{i\&j=i}\sum_{i\&k=i}A_jB_k \\
&=\sum_{i\&(j\&k)=i}A_jB_k \\
&= FCT_i
\end{aligned}
\]

我们发现 and 运算也是满足 \(a\&b=a,a\&c=a \to a\&(b\&c)=a\) 的

所以它可以

问题不大

接下来我们仍借用原来的定义进行分析

显然,我们发现 \(H\) 数组是不受 \(Q\) 的数组影响的

但是我们发现 \(Q\) 数组需加上 \(H\) 数组

所以

\(FWT:[Q+H]+[H]\)

\(IFWT:[Q-H]+[H]\)

\(OI-WiKi\ Std\)

void And(ll *a, ll type) {
for (ll x = 2; x <= n; x <<= 1) {
ll k = x >> 1;
for (ll i = 0; i < n; i += x) {
for (ll j = 0; j < k; j++) {
(a[i + j] += a[i + j + k] * type) %= P;
}
}
}
}

XOR

这个才是强度所在

这个的基础公式和前面小有区别

(以下作者并不明白为什么,但他是一种正确的构造)

首先设 \(a \# b\) 表示表示 \(x\& y\) 二进制表示中 \(1\) 数量的奇偶性

具体地讲,奇数时值为一,偶数时值为零

基础公式

\[FAT_i*FBT_i=FCT_i
\]
\[FAT_i=\sum_{i\# j=0}A_j-\sum_{i\# j=1}A_j
\]
\[C_i=\sum_{i=j\oplus k}{A_jB_k}
\]

接下来我们证一下构造的正确性

\[\begin{aligned}
FAT_iFBT_i&=\left(\sum_{i\# j=0}A_j-\sum_{i\# j=1}A_j\right)\left(\sum_{i\# k=0}B_k-\sum_{i\# k=1}B_k\right) \\
&=\left(\sum_{i\# j=0}A_j\sum_{i\# k=0}B_k+\sum_{i\# j=1}A_j\sum_{i\# k=1}B_k\right)-\left(\sum_{i\# j=0}A_j\sum_{i\# k=1}B_k+\sum_{i\# j=1}A_j\sum_{i\# k=0}B_k\right) \\
&=\sum_{(j\oplus k)\# i=0}A_jB_k-\sum_{(j\oplus k)\# i=1}A_jB_k \\
&=FCT_i
\end{aligned}
\]

如你所见,这个公式不太像是给人看的,所以我们解释一下

Line 1: 根据基础公式带入

Line 2: 乘法分配律

Line 3: 这一步的过程比较恶心,我们其实本质上就是要证明 \((i\#j)\oplus(i\#k)=i\#(j\oplus k)\)

Line 4: 定义带入

然后我们看一下 \((i\#j)\oplus(i\#k)=i\#(j\oplus k)\)

问题是:他对吗?

我也不知道好像吧。。。

我们例证一下

\(i=1101\ j=1001\ k=10\)

左边\(=0\oplus0=0\)

右边\(=1101\#0=0\)

好了就这样吧

接下来我们看一下这个 \(FWT\) 咋求

首先分治是一定的

然后我们考虑 \(Q\) 和 \(H\) 数组搞完变成什么了

先看我们的 \(Q\) 数组

首先他自己原来的 \(Value\) 可以用

其次我们考虑另一边的 \(H\) 数组

我们每一次都是不考虑他们的前缀的

所以呢?

所以右边和他位置相对应的 \(H\) 数组他在做这个 \(FWT\) 的时候他的方式和左边是一样的

而当前左边的首位为零

与完并没有什么影响

所以左边应为 \([Q+H]\)

后半部分呢?

左边因为最高位是零也可以直接加到右边

右边的 \(H\) 由于最高位给补了一个一而导致所有的东西全反了

\(SO\)

\([Q+H]+[Q-H]\)

反向操作也很简单啦

\([(Q+H)/2]+[(Q-H)/2]\)

这不就被我们口胡出来了吗!

\(Code\ From\ Wiki\)

void Xor(ll *a, ll type) {
for (ll x = 2; x <= n; x <<= 1) {
ll k = x >> 1;
for (ll i = 0; i < n; i += x) {
for (ll j = 0; j < k; j++) {
(a[i + j] += a[i + j + k]) %= P;
(a[i + j + k] = a[i + j] - a[i + j + k] * 2) %= P;
(a[i + j] *= type) %= P;
(a[i + j + k] *= type) %= P;
}
}
}
}

现在你可以水一个紫题 P4717

Tips

  1. 建议按照 \(WiKi\) 的模板的马蜂,因为他如果把反操作单独拆开可能函数的数量太多
  2. \(FWT\) 不需要二进制逆序!!!!!
  3. 这东西只有加减,所以可以取模,爱模多少模多少

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000009;
const ll Mod=998244353,Inv=499122177;
int n;
ll a[N],b[N],ta[N],tb[N],ans[N];
void MUL(ll *a,const ll *b){
for(int i=0;i<n;i++)a[i]=(a[i]*b[i])%Mod;
}
void SHOW(const ll *x){
for(int i=0;i<n;i++)printf("%lld ",x[i]);
puts("");
}
void OR(const ll *_x,ll *x,ll type){
int tmp;
for(int i=0;i<n;i++)x[i]=_x[i];
for(int l=2;l<=n;l<<=1){
tmp=l>>1;
for(int i=0;i<n;i+=l)for(int j=i;j<i+tmp;j++)
x[j+tmp]=((x[j+tmp]+type*x[j])%Mod+Mod)%Mod;
}
}
void AND(const ll *_x,ll *x,ll type){
int tmp;
for(int i=0;i<n;i++)x[i]=_x[i];
for(int l=2;l<=n;l<<=1){
tmp=l>>1;
for(int i=0;i<n;i+=l)for(int j=i;j<i+tmp;j++)
x[j]=((x[j]+type*x[j+tmp])%Mod+Mod)%Mod;
}
}
void XOR(const ll *_x,ll *x,ll type){
int tmp;
ll Q,H;
for(int i=0;i<n;i++)x[i]=_x[i];
for(int l=2;l<=n;l<<=1){
tmp=l>>1;
for(int i=0;i<n;i+=l)for(int j=i;j<i+tmp;j++){
Q=x[j],H=x[j+tmp];
x[j]=(Q+H)%Mod*type%Mod;
x[j+tmp]=((Q-H)%Mod*type%Mod+Mod)%Mod;
}
}
}
int main(){
int tmp;
scanf("%d",&tmp),n=1<<tmp;
for(int i=0;i<n;i++)scanf("%lld",&a[i]);
for(int i=0;i<n;i++)scanf("%lld",&b[i]);
OR(a,ta,1),OR(b,tb,1),MUL(ta,tb),OR(ta,ans,-1),SHOW(ans);
AND(a,ta,1),AND(b,tb,1),MUL(ta,tb),AND(ta,ans,-1),SHOW(ans);
XOR(a,ta,1),XOR(b,tb,1),MUL(ta,tb),XOR(ta,ans,Inv),SHOW(ans);
return 0;
}

FFT & NTT & FWT 基础的更多相关文章

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

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

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

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

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

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

  4. FFT/NTT基础题总结

    在学各种数各种反演之前把以前做的$FFT$/$NTT$的题整理一遍 还请数论$dalao$口下留情 T1快速傅立叶之二 题目中要求求出 $c_k=\sum\limits_{i=k}^{n-1}a_i* ...

  5. FFT&NTT数学解释

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

  6. FFT \ NTT总结(多项式的构造方法)

    前言.FFT  NTT 算法 网上有很多,这里不再赘述. 模板见我的代码库: FFT:戳我 NTT:戳我 正经向:FFT题目解题思路 \(FFT\)这个玩意不可能直接裸考的..... 其实一般\(FF ...

  7. FFT/NTT/MTT学习笔记

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

  8. FFT&NTT总结

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

  9. 快速构造FFT/NTT

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

  10. FFT/NTT模板 既 HDU1402 A * B Problem Plus

    @(学习笔记)[FFT, NTT] Problem Description Calculate A * B. Input Each line will contain two integers A a ...

随机推荐

  1. HashMap源码解析-JDK18

    引言 HashMap在JDK1.8和1.7中差异较大,在JDK1.8中HashMap引入了红黑树,优化减少了哈希冲突,提高了哈希表的存取效率. 本篇文章分析的就是JDK1.8中的HashMap源码. ...

  2. C# Newtonsoft.Json JObject常用方法

    1.创建-用匿名对象创建 JObject JObject ob = JObject.FromObject(new { RPT_ID = "getList", pageSize = ...

  3. protocol buffers(protobuf)安装教程

    本文按照mac讲解protobuf的安装,windows上比较好安装按照mac的基本流程就可以安装成功,mac上的安装有的时候比较容易出现问题 一.通过brew的方式安装(仅Mac) 需要mac中存在 ...

  4. SqlServer还原数据库出现“无法在服务器上访问指定的路径或文件”提示的解决办法

    1.问题描述 出现的错误信息如下图所示: 2.解决办法 打开SqlServer配置管理器,点击SQL Server服务,点击右侧的"SQL Server (MSSQLSERVER)" ...

  5. .NET最佳实践:避免滥用Task.Run

    在 C# 中,Task.Run 是用来在后台线程中执行异步任务的一个常见方法. 它非常适用于需要并行处理的场景,但如果不加以谨慎使用,可能会导致额外的线程池调度,进而影响程序的性能. 什么是线程池? ...

  6. Q:Win10关闭内存压缩功能

    微软在Win10中就已经启用了内存压缩机制,在Win11当中继续了这一设定. 通过任务管理器查看. taskmgr ·通过命令行查看. 使用系统管理员权限,打开PowerShell,然后输入以下命令: ...

  7. 记一次腾讯云轻量级服务器安装mysql配置完成后,外网无法访问问题

    一.配置信息正常 1.防火墙配置通过 2.mysql端口正常启动netstat -antlp | grep 3306 3.配置都正常,但是telnet访问不通超时Operation timed out ...

  8. .Net 6 配置日志

    前言   .Net 6 与之前的配置有点不一样了记录下日志配置方式. 当前日志以Serilog为例,.Net 6 的日志由内置的Logger获取,然后可以交给Serilog|NLog等框架处理, 框架 ...

  9. WPF Expander style

    <!--ExpanderStyle--> <Style x:Key="ExpanderStyleOne" TargetType="{x:Type Exp ...

  10. [ABC227E] Swap 题解

    考试一道题题解. 30pts:枚举所有串,\(check\) 是否可行. 60pts:做 \(bfs\),暴力推演变化过程,用 \(map\) 去重,时间复杂度 \(O(nC_{n}^{n/3}C_{ ...