洛谷P4245 模板 任意模數多項式乘法

2022-06-13 14:30:09 字數 1804 閱讀 1335

給定 \(2\) 個多項式 \(f(x), g(x)\) ,請求出 \(f(x) * g(x)\)。

係數對 \(p\) 取模,且不保證\(p\) 可以分解成 \(p = a \cdot 2^k + 1\) 之形式。

\(n\leq 10^5;a,b\leq 10^9;p\leq 10^9+9\)。

不保證 \(p\) 是 ntt 模數,所以不能直接用 ntt 做。

一般有兩種處理方法,一是用三模數 ntt,最後 crt 合併,精度可達 \(10^\)。另一種是拆位 fft。也稱 mtt。

拆位 fft 思路很簡單,將多項式每一位係數拆成兩部分 \(a_1,a_2\),其中 \(a_1\) 是 \(a\) 在二進位制下前十五位,\(a_2\) 是 \(a\) 在二進位制下後十五位。

那麼\[(f*g)[i]=(2^a_1[i]+a_2[i])\times (2^b_1[i]+b_2[i])

\]\[=2^a_1[i]a_2[i]+2^(a_1[i]b_2[i]+a_2[i]b_1[i])+a_2[i]b_2[i]

\]這樣一頓亂搞之後,卷積後每一項係數不超過 \(n\times (p^})^2=np\leq 10^\)。可以用 long double 強行存下。

這樣的話只需要 \(4\) 次 dft 和 \(3\) 次 idft 即可。

但是依然有更優的辦法。我們設複多項式 \(f'[i]=a_1[i]+a_2[i]i\),\(g'[i]=a_1[i]-a_2[i]i\),\(h'[i]=b_1[i]+b_2[i]i\),那麼

\[(f'*h')[i]=a_1[i]b_1[i]-a_2[i]b_2[i]+i(a_1[i]b_2[i]+a_2[i]b_1[i])

\]\[(g'*h')[i]=a_1[i]b_1[i]+a_2[i]b_2[i]+i(a_1[i]b_2[i]-a_2[i]b_1[i])

\]那麼

\[(f'*h')[i]+(g'*h')[i]=2a_1[i]b_1[i]+2a_1[i]b_2[i]i

\]\[(f'*h')[i]-(g'*h')[i]=-2a_2[i]b_2[i]+2a_2[i]b_1[i]i

\]我們只需要 \(3\) 次 dft 和 \(2\) 次 idft 即可。

注意為了保證精度,最好預處理單位根。

時間複雜度 \(o(n\log n)\)。

事實上我寫的 5 次 fft 還沒有 quantask 7 次的做法快 /kk。

#include #define cp complexusing namespace std;

typedef long long ll;

typedef long double ld;

const int n=300010;

const ld pi=acos(-1);

int n,m,lim,mod,rev[n];

cp f[n],g[n],h[n],w[n];

void fft(cp *f,int tag)

for (int i=0,x;i<=m;i++)

lim=1;

while (lim<=n+m) lim<<=1;

for (int i=0;i>1]>>1)|((i&1)?(lim>>1):0);

fft(f,1); fft(g,1); fft(h,1);

for (int i=0;if[i]*=h[i],g[i]*=h[i];

fft(f,-1); fft(g,-1);

for (int i=0;i<=n+m;i++)

return 0;

}

P4245 模板 任意模數多項式乘法

首先這類問題指的是對於乙個非ntt模數,我們如何計算多項式乘法,對於ntt不容易找到單位根,對於fft又會爆精度。方法1 三模數ntt 尋找三個大模數最後crt合併即可 方法2 mtt 將係數拆分為兩部分,分別是m的倍數和餘數,然後我們只需要對其分別處理即可,但是這樣暴力的做一共需要7次fft複雜度...

P4245 模板 任意模數多項式乘法

兩個多項式,求它們的乘積模 p 方法好像挺多,我用的是最簡單的一種就是,先定乙個常數 sqq 一般是 sqrt q 把乙個項的數 x 拆成 k sqq r 然後把 f 的 k 丟進 a r 丟進 b g 的 k 丟進 c r 丟進 d 然後對於 a c 的部分就是 sqq 2 的部分,a d b c...

P4245 模板 任意模數多項式乘法

首先這類問題指的是對於乙個非ntt模數,我們如何計算多項式乘法,對於ntt不容易找到單位根,對於fft又會爆精度。方法1 三模數ntt 尋找三個大模數最後crt合併即可 方法2 mtt 將係數拆分為兩部分,分別是m的倍數和餘數,然後我們只需要對其分別處理即可,但是這樣暴力的做一共需要7次fft複雜度...