看了好長時間的fft和ntt啊qwq在原根那塊磨蹭了好久_(:з」∠)_
首先設答案多項式的長度拓展到2的冪次後為n,我們只要求出乙個g(不是原根)滿足\(i\in \,g^i\)互不相同,且\(g^n=1\)。
把這個g當做「fft裡面的主n次單位根」的類似物。
而且\(g^=-1\),因為\(g^\)與\(g^n\)不相同且\((g^)^2=g^n=1\),所以\(g^\)只能是-1。
剩下的只要選乙個夠大的模數滿足答案多項式的所有係數都小於這個模數就可以了。
我選的模數是998244353(\(7×17×2^+1\),乙個質數,uoj模數)。不是所有的模數p都可以,像\(10^9+7\)就不可以,因為此時p-1的因子2的指數不夠大。只有p-1的因子2的指數c足夠大,\(2^c>n\)時才可以。
這裡我寫了乙個暴力找到了乙個g=646。
//998244353
#include#include#includeusing namespace std;
typedef long long ll;
const int p = 998244353;
const int n = 1048576;
bool can[p];
int main()
can[re] = true;
re = re * num % p;
} if (!flag || re != num)
continue;
} printf("%d\n", num);
return 0;
} /*
freopen("tab.txt", "w", stdout);
int num = 646; ll ret = 1;
for (int i = 1; i <= (n >> 1); ++i)
*/}
求出g後就可以ntt了,不過也需要預處理一些分治實現nnt時(一般是迭代實現,這裡也是)n不斷除2變小需要用到的不同的「主n次單位根」和「主n次單位根的逆元」。
一開始我對原根(及主n次單位根)的定義比較模糊,沒有預處理「主n次單位根」的逆元而直接用負的「主n次單位根」導致逆dnnt出錯qwq
ntt有取模果然慢啊,不過沒有fft的複數精度誤差。
#include#include#includeusing namespace std;
typedef long long ll;
const int p = 998244353;
const int n = 1048576;
const int g = 646;
int rev[n], wn[23], nwn[23], n;
int ipow(int a, int b)
return ret;
}void dnt(int *a, int *a, int flag)
} }if (flag == -1)
}int da[n], db[n], dc[n];
void ntt(int *a, int lena, int *b, int lenb, int *ans, int n)
void init()
int num = n, tot = 0, res;
while (num)
n = 1 << tot;
for (int i = 0; i < n; ++i)
rev[i] = res; }}
int lena, lenb, a[n >> 1], b[n >> 1], ans[n];
int main()
乙個板子都寫了這麼長時間省選是要滾粗嗎→_→ UOJ 34 多項式乘法
快速傅利葉變換 關於fft網上的教材不多,而且大多與演算法問題關係不大。強烈推薦乙個。這個講得真的很不錯 從多項式乘法到快速傅利葉變換 本弱數學知識不夠多,複數 單位根之類的知識都是下午臨時補的。從下午開始看fft,看到晚上,總算大概是把遞迴版fft的思路看懂了吧。迭代版的還沒看懂。有空慢慢鑽研 u...
UOJ 34 多項式乘法
統計這是一道模板題。給你兩個多項式,請輸出乘起來後的多項式。第一行兩個整數 n n 和 mm 分別表示兩個多項式的次數。第二行 n 1 n 1 個整數,分別表示第乙個多項式的 0 0 到 nn 次項前的係數。第三行 m 1 m 1 個整數,分別表示第乙個多項式的 0 0 到 mm 次項前的係數。一行...
UOJ 34 多項式乘法
fft模板 迭代的還沒會 先寫了個遞迴的 define的pi 我也是神了!少上一位就會wa 模板看的hzwer的 因為 pi較短 所以遞迴的跑的和迭代的一樣快 23333333 還差的幾點 1.acos要用 2.complex要自己寫 yts1999大爺說會被卡 3.要改成迭代的 1 include...