版权声明:本博客内容基本为原创,如有问题欢迎联系,未经允许请勿转载 https://blog.csdn.net/qq_41955236/article/details/82016507
这是一道模板题。
给你两个多项式,请输出乘起来后的多项式。
输入格式
第一行两个整数 nn 和 mm,分别表示两个多项式的次数。
第二行 n+1n+1 个整数,表示第一个多项式的 00 到 nn 次项系数。
第三行 m+1m+1 个整数,表示第二个多项式的 00 到 mm 次项系数。
输出格式
一行 n+m+1n+m+1 个整数,表示乘起来后的多项式的 00 到 n+mn+m 次项系数。
样例一
input
1 2
1 2
1 2 1
output
1 4 5 2
explanation
(1+2x)⋅(1+2x+x2)=1+4x+5x2+2x3(1+2x)⋅(1+2x+x2)=1+4x+5x2+2x3。
限制与约定
0≤n,m≤1050≤n,m≤105,保证输入中的系数大于等于 00 且小于等于 99。
时间限制:1s1s
空间限制:256MB
模板题就不解释了吧,多项式乘法,用了NTT(数论变换)。表示不是很懂但是。。模板留着用用吧。。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1 << 20;
typedef long long ll;
const ll mo = 998244353;
ll fpow(ll a, ll b)
{
ll ans = 1;
while (b > 0) { if (b & 1)ans = ans * a%mo; b >>= 1; a = a * a%mo; }
return ans;
}
struct C
{
ll a;
C() {}
C(ll a) :a(a) {}
C operator = (int a) { *this = C(a); return *this; }
C operator + (const C &t) { return C(a + t.a >= mo ? (a + t.a - mo) : (a + t.a)); }
C operator - (const C &t) { return C(a - t.a < 0 ? (a - t.a + mo) : (a - t.a)); }
C operator * (const C &t) { return C(a*t.a%mo); }
};
C wn(int n, int f)
{
return fpow(3, (mo - 1) / n >> 1);
}
C inv(int n)
{
return fpow(n, mo - 2);
}
C a[maxn], b[maxn], c[maxn];
int g[maxn];
void NTT(C *a, int n, int f)
{
for (int i = 0; i < n; i++)if (i > g[i])swap(a[i], a[g[i]]);
for (int i = 1; i <= n; i <<= 1)
{
C w = wn(i, f), x, y;
for (int j = 0; j < n; j += i + i)
{
C e; e = 1;
for (int k = 0; k < i; e = e * w, k++)
{
x = a[j + k];
y = a[j + k + i] * e;
a[j + k] = x + y;
a[j + k + i] = x - y;
}
}
}
if (f == -1)
{
C Inv = inv(n);
for (int i = 0; i < n / 2; i++)swap(a[i], a[n - i]);
for (int i = 0; i < n; i++)a[i] = a[i] * Inv;
}
}
void conv(C *a, int n, C *b, int m, C *c)
{
int k = 0, s = 2;
while ((1 << k) < max(n, m) + 1)k++, s <<= 1;
for (int i = 1; i < s; i++)g[i] = (g[i / 2] / 2) | ((i & 1) << k);
NTT(a, s, 1);
NTT(b, s, 1);
for (int i = 0; i < s; i++)c[i] = a[i] * b[i];
NTT(c, s, -1);
}
int main()
{
int n, m;
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]);
conv(a, n, b, m, c);
for (int i = 0; i <= n + m; i++)printf("%lld ", c[i]);
return 0;
}
第二个是double型的FFT,可以处理实数但是跑的会稍微慢一点
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1 << 18;
typedef complex<double> C;
C wn(int n, int f)
{
return C(cos(acos(-1.0) / n), f*sin((acos(-1.0)) / n));
}
C inv(int n)
{
return C(1.0 / n, 0);
}
C a[maxn], b[maxn], c[maxn];
int g[maxn];
void FFT(C *a, int n, int f)
{
for (int i = 0; i < n; i++)if (i > g[i])swap(a[i], a[g[i]]);
for (int i = 1; i < n; i <<= 1)
{
C w = wn(i, f), x, y;
for (int j = 0; j < n; j += i + i)
{
C e; e = 1;
for (int k = 0; k < i; e = e * w, k++)
{
x = a[j + k];
y = a[j + k + i] * e;
a[j + k] = x + y;
a[j + k + i] = x - y;
}
}
}
if (f == -1)
{
C Inv = inv(n);
for (int i = 0; i < n; i++)a[i] = a[i] * Inv;
}
}
void conv(C *a, int n, C *b, int m, C *c)
{
int k = 0, s = 2;
while ((1 << k) < max(n, m) + 1)k++, s <<= 1;
for (int i = 1; i < s; i++)g[i] = (g[i / 2] / 2) | ((i & 1) << k);
FFT(a, s, 1);
FFT(b, s, 1);
for (int i = 0; i < s; i++)c[i] = a[i] * b[i];
FFT(c, s, -1);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i <= n; i++)scanf("%lf", &a[i]);
for (int i = 0; i <= m; i++)scanf("%lf", &b[i]);
conv(a, n, b, m, c);
for (int i = 0; i <= n + m; i++)printf("%d ", (int)(c[i].real() + 0.5));
return 0;
}