【模板】快速数论变换(NTT)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40727946/article/details/86516207

数论优化的快速傅里叶变换
快速数论变换(NTT)是快速傅里叶变换(FFT)在数论基础上的实现

/*
时间复杂度O(NlongN)
*/
#include<bits/stdc++.h> 
using namespace std;
const int N = 300100, P = 998244353;	//系数对 p 取模
int qpow(int x, int y)
{
	int res(1);
	while (y)
	{
		if (y & 1) res = 1ll * res*x%P;
		x = 1ll * x*x%P;
		y >>= 1;
	}
	return res;
}

int r[N];

void ntt(int *x, int lim, int opt)
{
	int i, j, k, m, gn, g, tmp;
	for (i = 0; i < lim; ++i)
		if (r[i] < i)
			swap(x[i], x[r[i]]);
	for (m = 2; m <= lim; m <<= 1)
	{
		k = m >> 1;
		gn = qpow(3, (P - 1) / m);
		for (i = 0; i < lim; i += m)
		{
			g = 1;
			for (j = 0; j < k; ++j, g = 1ll * g*gn%P)
			{
				tmp = 1ll * x[i + j + k] * g%P;
				x[i + j + k] = (x[i + j] - tmp + P) % P;
				x[i + j] = (x[i + j] + tmp) % P;
			}
		}
	}
	if (opt == -1)
	{
		reverse(x + 1, x + lim);
		int inv = qpow(lim, P - 2);
		for (i = 0; i < lim; ++i)
			x[i] = 1ll * x[i] * inv%P;
	}
}
int A[N], B[N], C[N];
char a[N], b[N];
int main()
{
	while (~scanf("%s", &a))
	{
		int i, lim = 1, n;
		n = strlen(a);
		for (i = 0; i < n; ++i) A[i] = a[n - i - 1] - '0';
		while (lim < n * 2) lim <<= 1;
		scanf("%s", &b);
		n = strlen(b);
		for (i = 0; i < n; ++i) B[i] = b[n - i - 1] - '0';
		while (lim < n * 2) lim <<= 1;
		for (i = 0; i < lim; ++i)
			r[i] = (i & 1)*(lim >> 1) + (r[i >> 1] >> 1);
		ntt(A, lim, 1); ntt(B, lim, 1);
		for (i = 0; i < lim; ++i)
			C[i] = 1ll * A[i] * B[i] % P;
		ntt(C, lim, -1);
		//进行乘法进位处理 
		for (i = 0; i < lim; ++i)
		{
			C[i + 1] += C[i] / 10;
			C[i] %= 10;
		}
		int len = strlen(a) + strlen(b) - 1;
		while (C[len] <= 0 && len > 0)len--;
		for (i = len; i >= 0; --i)
			putchar(C[i] + '0');
		printf("\n");
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		memset(C, 0, sizeof(C));
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		memset(r, 0, sizeof(r));
	}
	return 0;
}
/*
HDU 1402
输入:
1
2
1000
2
输出:
2
2000

*/

猜你喜欢

转载自blog.csdn.net/qq_40727946/article/details/86516207