演算法筆記 FFT NTT

2022-03-05 03:47:17 字數 4017 閱讀 1184

本文不做證明,詳細證明請看如上資料。

fft在演算法競賽中主要用來加速多項式的乘法

普通是多項式乘法時間複雜度的是o(n2),而用fft求多項式的乘法可以使時間複雜度達到o(nlogn)

fft求多項式的乘法步驟主要如下圖

其中求值是將係數表達轉換成點值表達,帶入的自變數是wn=1的複數解,稱為dft

插值是將點值表達轉換成係數表達,稱為dft-1

dft 和 dft-1都可以用fft加速實現

這是遞迴版的fft

還有一種非遞迴的版本

我們發現葉子節點的下表的二進位制為:000   100   010   110    001  101   110    111

與它們的本身所對應的位置的二進位制:000   001  010   011    100   101    011   111

相反所以我們可以確定葉子節點的值,從下往上進行操作

求二進位制反轉的**(其中l是二進位制位):

for (int i = 0; i < n; i++)
假設現在r[i]的二進位制是abcd,沒有操作之前的r[i>>1]是0abc,操作之後的是cba0,再右移是0cba,再判斷原來的d是不是1在最高位放1或0,就剛好是反轉的結果

模板:遞迴版(以求大數乘法為例):

#includeusing

namespace

std;

#define fi first

#define se second

#define pi acos(-1.0)

#define ll long long

#define mp make_pair

#define pb push_back

#define ls rt<<1, l, m

#define rs rt<<1|1, m+1, r

#define ull unsigned ll

#define pll pair#define pii pair#define piii pair#define mem(a, b) memset(a, b, sizeof(a))

#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);

//head

typedef complex

cd;const

int n = 2e5 + 5

;char

a[n], b[n];

cd a[n], b[n];

inttmp[n];

void fft(cd *x, int n, int

type)

fft(l, n>>1

, type);

fft(r, n>>1

, type);

cd wn(cos(

2*pi/n), sin(type*2*pi/n)), w(1, 0

), t;

for(int i = 0; i < n>>1; i++, w *=wn)

}int

main()

inti;

for (i = m; i >= 1; i--) if(tmp[i]) break

;

for (i; i >= 0; i--) printf("%d"

, tmp[i]);

printf("\n

");}

return0;

}

fft非遞迴版模板:

typedef complexcd;

const

int n = 2e5 + 5

;cd a[n], b[n];

intr[n];

void fft(cd *x, int n, int

type) }}

if(type == -1) }

intmain()

ps:手寫complex類+非遞迴版最快

ntt模板:

#includeusing

namespace

std;

/*469762049--3

998244353--3

1004535809--3

1e9+7 -- 5

(g 是mod(r*2^k+1)的原根)

素數 r k g

3 1 1 2

5 1 2 2

17 1 4 3

97 3 5 5

193 3 6 5

257 1 8 3

7681 15 9 17

12289 3 12 11

40961 5 13 3

65537 1 16 3

786433 3 18 10

5767169 11 19 3

7340033 7 20 3

23068673 11 21 3

104857601 25 22 3

167772161 5 25 3

469762049 7 26 3

1004535809 479 21 3

2013265921 15 27 31

2281701377 17 27 3

3221225473 3 30 5

75161927681 35 31 3

77309411329 9 33 7

*/const

int n = 300100, p = 998244353

;inline

int qpow(int x, int

y)

return

res;

}int

r[n];

void ntt(int *x, int n, int

opt)

}}

if (opt == -1) }

inta[n], b[n], c[n];

intmain()

任意模數ntt模板:

const

int maxn = 400005,maxm = 100005

;int pr=;

intr[maxn];

inline ll qpow(ll a,ll b,ll p)

struct

fft }

}if (f == 1) return

;

int nv = qpow(n,p - 2,p); reverse(a + 1,a +n);

for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv %p;

}}fft[3];

intf[maxn],g[maxn],b[maxn],deg1,deg2,deg,md;

ll ans[maxn];

ll inv(ll n,ll p)

ll mul(ll a,ll b,ll p)

void

crt()

}void

conv()

}int

main()

FFT NTT 學習筆記

顯然因為我不會數學,所以這篇文章會非常 感性 將兩個多項式乘起來,即求 f g h 多項式的項數 n le10 5 複數複數是指形如 x yi 的數,高中會教。它的四則運算法則是這樣的 令 p,q 為兩個複數 p pm q x p pm x q y p pm y q i p times q x px...

FFT NTT數學解釋

fft和ntt真是噩夢呢 既然被fft和ntt坑夠了,坑一下其他的人也未嘗不可呢 設有乙個數a,使得an 1,其中n為滿足an 1的最小正整數 滿足條件的a有哪些呢?更寬泛地說,只要在乙個集合中定義了加法和乘法,而且二者滿足 這些基本上是小學學的吧,除了最後一點之外,其他都是廢話 那麼裡面滿足an ...

FFT NTT中檔題總結

被deepinc 怕了,把一些題放到這裡來 其實這道題放到中檔題也不太合適,個人感覺真的很難,機房裡好像都是頹的題解 因為期望的可加性,把每個點的貢獻單獨處理,即求期望深度 考慮 y 對 x 的貢獻 當且僅當 x y 的路徑上第乙個點就選 y y 才能成為 x 的祖先 所以 y 對 x 的貢獻就是 ...