多项式算法 学习笔记
NTT
真的学不会,所以直接背代码:
- 刚开始求一个 \(len\) 的目的,是因为长度必须是 \(2\) 的次幂。
- 后来求了一个 \(rev\) 数组,背下来就行了。
- 再后来是把 \(a\) 和 \(b\) 的长度补位到 \(len\)。
- 然后分别给 \(a\) 和 \(b\) 执行 NTT 函数,这个是系数表示法转点值表示法,所以第二项是 \(1\)。
- 然后直接每一位都相乘。
- 然后把算好的 \(a\) 从点值转化为系数。
- 最后数组的每个值都需要除以 \(len\),具体原因我也不知道,反正除就行了,除完就是最终答案。
- 最后一个是把数组中多余的 \(0\) 去除掉,然后返回。
- NTT 函数直接背就行了。
折叠块会出奇怪的问题,我也不知道咋回事。
#include<bits/stdc++.h>
#define int long long
using namespace std;
auto mread = [](){int x;scanf("%lld", &x);return x;};
const int N = 5e6 + 5, MOD = 998244353, g = 3, gi = 332748118;
int n = mread(), m = mread(), rev[N];
int ksm(int x, int k){
int ans = 1, now = x;
while(k){
if(k & 1)
ans = ans * now % MOD;
now = now * now % MOD;
k >>= 1;
}
return ans;
}
struct node{
vector<int> v;
void NTT(int n, int type){
for(int i = 0; i < n; i ++)
if(i < rev[i])
swap(v[i], v[rev[i]]);
for(int i = 1; i < n; i <<= 1){
int gn = ksm(type ? g : gi, (MOD - 1) / (i << 1));
for(int j = 0; j < n; j += (i << 1)){
int g0 = 1;
for(int k = 0; k < i; k ++, g0 = g0 * gn % MOD){
int x = v[j + k], y = g0 * v[i + j + k] % MOD;
v[j + k] = (x + y) % MOD;
v[i + j + k] = (x - y + MOD) % MOD;
}
}
}
}
friend node operator *(node a, node b){
int len = 1;
while(len < (a.v.size() + b.v.size()))
len <<= 1;
for(int i = 0; i < len; i ++)
rev[i] = (i & 1) * (len >> 1) + (rev[i >> 1] >> 1);
while(a.v.size() < len)
a.v.push_back(0);
while(b.v.size() < len)
b.v.push_back(0);
a.NTT(len, 1);
b.NTT(len, 1);
for(int i = 0; i < len; i ++)
a.v[i] = a.v[i] * b.v[i] % MOD;
a.NTT(len, 0);
int inv = ksm(len, MOD - 2);
for(int i = 0; i < len; i ++)
a.v[i] = a.v[i] * inv % MOD;
while(a.v.back() == 0)
a.v.pop_back();
return a;
}
}a, b;
signed main(){
return 0;
}

浙公网安备 33010602011771号