給定 \(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複雜度...