首页 > 其他分享 >【瞎口胡】快速数论变换 NTT

【瞎口胡】快速数论变换 NTT

时间:2022-09-01 17:25:21浏览次数:85  
标签:23 数论 瞎口 单位根 NTT varphi int omega 998244353

在 FFT 中,因为是浮点数计算因此会掉精度。如果你不知道 FFT 是什么,请阅读这里

如果在模意义下,我们可以选择不使用复平面的单位根,而是模意义下的单位根。

考虑单位根的性质:

  • \(\omega_{n}^{n}=\omega_{n}^{0}=1\)
  • 对于 \(n=2m\),\(\omega_{n}^{k}=-\omega_{n}^{k+m}\)
  • \(\omega_{n}^{k} = \omega_{2n}^{2k}\)

一个常见的 NTT 模数是 \(998244353=7 \times 17 \times 2^{23}+1\)(它是一个质数)。它有一个原根 \(3\)。别忘了,模 \(p\) 意义下的原根 \(a\) 满足 \(a^{\varphi(p)}\equiv 1 \pmod p\),并且不存在更小的指数 \(x\) 使得 \(a^{x} \equiv 1 \pmod p\)。

因为 \(\varphi(p = 998244353) = 998244352 = 7 \times 17 \times 2^{23}\),容易发现模意义下的 \(\omega_2 = a^{\frac 12 \varphi(p)}\),\(\omega_{4} = a^{\frac 14 \varphi(p)}\),以此类推。由 \(\varphi(p)\) 的唯一分解式可以发现,它最多有 \(2^{23}\) 次单位根。于是用 \(998244353\) 作为模数时,最多可以做 长度为 \(2^{23}\) 的多项式乘法。

模板 Luogu P1919 A*B Problem 升级版

题意

给定两个正整数 \(a,b\),输出它们的乘积。

\(1 \leq a,b \leq 10^{10^6}\)

题解

把数看成多项式,做 NTT 即可。

# include <bits/stdc++.h>

const int N=4000010,INF=0x3f3f3f3f,MOD=998244353;

typedef long long ll;

int w[30],winv[30]; // 998244353 = 7*17*2^23 w[i] = 2^i 等分单位根 
typedef std::vector <int> Poly;
int rev[N];
char A[N],B[N];
Poly F,G;
int ans[N<<1],anslen;

inline int read(void){
	int res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-')f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}
inline int qpow(ll d,ll p){
	ll ans=1;
	while(p){
		if(p&1)
			ans=ans*d%MOD;
		p>>=1,d=d*d%MOD;
	}
	return ans;
}
inline void init(void){
	for(int i=0;i<=23;++i){
		w[i]=qpow(3,(MOD-1)/(1<<i)),winv[i]=qpow(w[i],MOD-2);
        // 2^i 次单位根及其逆元
	}
	return;
}
inline void Revchange(Poly &f,int len){ // 蝴蝶变换
	for(int i=1;i<len;++i){
		rev[i]=(rev[i>>1]>>1)|((i&1)*(len>>1));
	}
	for(int i=0;i<len;++i){
		if(i<rev[i])
			std::swap(f[i],f[rev[i]]);
	}
	return;
}
void NTT(Poly &f,int len,int op){
	Revchange(f,len);
	for(int h=2,hpow=1;h<=len;h<<=1,++hpow){
		int wh=((op==1)?w[hpow]:winv[hpow]); // idft 的时候记得取逆元
		for(int j=0;j<len;j+=h){
			int noww=1;
			for(int k=j;k<j+h/2;++k){
				int u=f[k],v=1ll*noww*f[k+h/2]%MOD;
				f[k]=(u+v)%MOD,f[k+h/2]=((u-v)%MOD+MOD)%MOD;
				noww=1ll*noww*wh%MOD;
			}
		}
	}
	return;
}
int main(void){
	init();
	scanf("%s",A),scanf("%s",B);
	int n=strlen(A),m=strlen(B),maxlen=1;
	while(maxlen<=n+m-2){
		maxlen<<=1;
	}
	F.resize(maxlen+5),G.resize(maxlen+5);
	for(int i=0;i<n;++i){
		F[i]=A[n-i-1]-'0';
	}
	for(int i=0;i<m;++i){
		G[i]=B[m-i-1]-'0';
	}
	NTT(F,maxlen,1),NTT(G,maxlen,1);
	for(int i=0;i<maxlen;++i){
		F[i]=1ll*F[i]*G[i]%MOD;
	}
	NTT(F,maxlen,-1);
	for(int i=0;i<maxlen;++i)
		F[i]=1ll*F[i]*qpow(maxlen,MOD-2)%MOD,ans[i]=F[i];
	for(int i=0;i<maxlen+200;++i){
		ans[i+1]+=ans[i]/10,ans[i]%=10;
	}
	for(int i=maxlen+200;i>=0;--i){
		if(ans[i]){
			for(int j=i;j>=0;--j)
				printf("%d",ans[j]);
			return 0;
		}
	}
	return 0;
}

标签:23,数论,瞎口,单位根,NTT,varphi,int,omega,998244353
From: https://www.cnblogs.com/liuzongxin/p/16647204.html

相关文章

  • 【瞎口胡】多项式牛顿迭代
    前言如果完全不会求导和积分,以及泰勒展开,这里有一个实用性很强的教程3blue1brown-微积分的本质。多项式牛顿迭代给定函数\(G(x)\),求多项式\(F(x)\)使得\(G(F(x))......
  • 【瞎口胡】多项式操作
    前置快速傅里叶变换FFT多项式的基石操作。快速沃尔什变换FWT位运算卷积。鸽了。快速数论变换NTT把FFT搬到了模意义下,终于可以做计数问题啦。多项式牛顿......
  • 【瞎口胡】单位根反演
    单位根反演是用单位根来表示整除关系的东西。定义式\[\left[k\midn\right]=\dfrac{1}{k}\sum\limits_{i=0}^{k-1}\omega_k^{in}\]如果\(k\midn\),那么\(\omeg......
  • 【瞎口胡】Min-Max 容斥
    Min-Max容斥是通过容斥集合的最小值来得到集合最大值的一种方法。结合期望的线性性,我们得以计算几个随机变量最值的期望,它往往不和这些变量期望的最值相等。Min-Max容斥......
  • Mathematical Circus-数论-分类讨论
    codeforces MathematicalCircus-div2-B题意:给定n,k。是否能把(1--n)的数分成符合条件的(a,b)对。条件:(a+k)*b%4==0解:因为:原式=(a+k)*b≡0(mod4)ab+b*k≡0(mod4)若k>=4,b......
  • 【瞎口胡】多步容斥和二项式反演
    多步容斥多步容斥是指,对于\(n\)个集合\(A_1,A_2,\cdots,A_n\),有\[|A_1\cupA_2\cdots\cupA_n|=\sum\limits_{1\leqi\leqn}|A_i|-\sum\limits_{1\leqi<......
  • React报错之Property 'value' does not exist on type EventTarget
    正文从这开始~总览当event参数的类型不正确时,会产生"Property'value'doesnotexistontypeEventTarget"错误。为了解决该错误,将event的类型声明为React.ChangeEvent......
  • 数论笔记(Full Version)
    数论笔记(FullVersion)一、数论基础:1、整除:重新定义除法:对于计算式:\(a\divb\)来说,其结果可以变化为以下的式子:$$a=\lfloor\frac{a}{b}\rfloor+a\bmodb$$其......
  • 【AGC】AGC鉴权认证模式获取clientToken的方法
    ​近期有开发者在使用API方式接入Indexing服务时提出疑问,如何获取clientToken。其实AGC认证模式是基于clientToken鉴权方式,由云侧网关与AGC微服务实现的一套OAuth2标准鉴权......
  • 时隔多年,再次复习 CRT(数论全家桶)
    1.CRT中国剩余定理,用来求解同余方程组\begin{cases}x\equiva_1\pmod{m_1}\\x\equiva_2\pmod{m_2}\\x\equiva_3\pmod{m_3}\\…………\\x\equiva_n\pmod{m......