NTT(快速数论变换)
在取模的情况下,解决多项式乘法.
n,m表示多项式的次数,从低到高读入
const int NR = 1 << 22, g = 3, gi = 332748118, mod = 998244353;
//998244353的一个原根为3且998244353-1=2^23*119,3在模998244353意义下的逆元为332748118
int n, m, rev[NR]; //rev[i]为i的二进制翻转
long long a[NR], b[NR];
ll fast_power(ll a, ll k) //快速幂,a为底数,k为指数
{
ll res = 1;
while (k)
{
if (k & 1)
res = res * a % mod;
a = a * a % mod;
k >>= 1;
}
return res;
}
void NTT(ll* a, int n, int type) //NTT,type=1时系数表示法转点值表示法,否则点值表示法转系数表示法
{
for (int i = 0; i < n; ++i) //先将a变成最后的样子
if (i < rev[i])
swap(a[i], a[rev[i]]);
for (int i = 1; i < n; i <<= 1)
{ //在这之前NTT与FFT无异
ll gn = fast_power(type ? g : gi, (mod - 1) / (i << 1)); //单位原根g_n
for (int j = 0; j < n; j += (i << 1)) //枚举具体区间,j也就是区间右端点
{
ll g0 = 1;
for (int k = 0; k < i; ++k, g0 = g0 * gn % mod) //合并,记得要取模
{
ll x = a[j + k], y = g0 * a[i + j + k] % mod;
a[j + k] = (x + y) % mod;
a[i + j + k] = (x - y + mod) % mod;
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i <= n; ++i) //输入第一个多项式
scanf("%lld", a + i);
for (int i = 0; i <= m; ++i) //输入第二个多项式
scanf("%lld", b + i);
int len = 1, L = 0;
while (len <= n + m)
len <<= 1, L++;
for (int i = 0; i < len; ++i) //求rev
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
NTT(a, len, 1); //系数表示法转点值表示法
NTT(b, len, 1);
for (int i = 0; i <= len; ++i)
a[i] = a[i] * b[i] % mod; //O(n)乘法
NTT(a, len, 0); //点值表示法转系数表示法
ll inv = fast_power(len, mod - 2); //inv为len的逆元(费马小定理求逆元)
for (int i = 0; i <= n + m; ++i) //输出
printf("%lld ", a[i] * inv % mod); //除以len在模mod意义下即为乘以inv
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!