Luogu5205 【模板】多项式开根(NTT+多项式求逆)

  https://www.cnblogs.com/HocRiser/p/8207295.html 安利!

  写NTT把i<<=1写成了i<<=2,又调了一年。发现我的日常就是数组开小调调调,变量名写错调调调,反向判if调调调,退役吧。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define P 998244353
#define N 550000
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a[N],r[N],b[N],A[N],B[N],f[N],g[N],t;
int ksm(int a,int k)
{
	int s=1;
	for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
	return s;
}
int inv(int a){return ksm(a,P-2);}
void DFT(int n,int *a,int g)
{
	for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|(i&1)*(n>>1);
	for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
	for (int i=2;i<=n;i<<=1)
	{
		int wn=ksm(g,(P-1)/i);
		for (int j=0;j<n;j+=i)
		{
			int w=1;
			for (int k=j;k<j+(i>>1);k++,w=1ll*w*wn%P)
			{
				int x=a[k],y=1ll*w*a[k+(i>>1)]%P;
				a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P;
			}
		}
	}
}
void IDFT(int *a,int n)
{
	DFT(n,a,inv(3));
	int u=inv(n);
	for (int i=0;i<n;i++) a[i]=1ll*a[i]*u%P;
}
void mul(int *a,int *b,int n)
{
	DFT(n,a,3),DFT(n,b,3);
	for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%P;
	IDFT(a,n);
}
void Inv(int *a,int *b,int n)
{
	if (n==1) {for (int i=0;i<t;i++) b[i]=0;b[0]=inv(a[0]);return;}
	Inv(a,b,n>>1);
	for (int i=0;i<n;i++) A[i]=a[i];
	for (int i=n;i<(n<<1);i++) A[i]=0;
	n<<=1;
	DFT(n,A,3),DFT(n,b,3);
	for (int i=0;i<n;i++) b[i]=1ll*b[i]*(P+2-1ll*A[i]*b[i]%P)%P;
	IDFT(b,n);
	n>>=1;
	for (int i=n;i<(n<<1);i++) b[i]=0;
}
void Sqrt(int *a,int *b,int n)
{
	if (n==1) {for (int i=0;i<t;i++) b[i]=0;b[0]=1;return;}
	Sqrt(a,b,n>>1);Inv(b,B,n);
	for (int i=0;i<n;i++) A[i]=a[i];
	for (int i=n;i<(n<<1);i++) A[i]=0;
	n<<=1;
	DFT(n,A,3),DFT(n,b,3),DFT(n,B,3);
	int inv2=inv(2);
	for (int i=0;i<n;i++) b[i]=(b[i]+1ll*A[i]*B[i]%P)*inv2%P;
	IDFT(b,n);
	n>>=1;
	for (int i=n;i<(n<<1);i++) b[i]=0;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("sqrt.in","r",stdin);
	freopen("sqrt.out","w",stdout);
	const char LL[]="%I64d\n";
#else
	const char LL[]="%lld\n";
#endif
	n=read();
	for (int i=0;i<n;i++) a[i]=read();
	t=1;while (t<=n) t<<=1;
	Sqrt(a,b,t);
	for (int i=0;i<n;i++) printf("%d ",b[i]);
	return 0;
}

  

原文地址:https://www.cnblogs.com/Gloid/p/10386469.html

时间: 2024-08-30 13:57:14

Luogu5205 【模板】多项式开根(NTT+多项式求逆)的相关文章

CF438E The Child and Binary Tree(生成函数+多项式开根+多项式求逆)

传送门 可以……这很多项式开根模板……而且也完全不知道大佬们怎么把这题的式子推出来的…… 首先,这题需要多项式开根和多项式求逆.多项式求逆看这里->这里,这里讲一讲多项式开根 多项式开方:已知多项式$A$,求多项式$B$满足$A^2\equiv B\pmod{x^n}$(和多项式求逆一样这里需要取模,否则$A$可能会有无数项) 假设我们已经求出$A'^2\equiv B\pmod{x^n}$,考虑如何计算出$A^2\equiv B\pmod{x^{2n}}$ 首先肯定存在$A^2\equiv B

[Codeforces438E][bzoj3625] 小朋友和二叉树 [多项式求逆+多项式开根]

题面 传送门 思路 首先,我们把这个输入的点的生成函数搞出来: \(C=\sum_{i=0}^{lim}s_ix^i\) 其中\(lim\)为集合里面出现过的最大的数,\(s_i\)表示大小为\(i\)的数是否出现过 我们再设另外一个函数\(F\),定义\(F_k\)表示总权值为\(k\)的二叉树个数 那么,一个二叉树显然可以通过两个子树(可以权值为0,也就是空子树)和一个节点构成 那么有如下求\(F\)的式子 \(F_0=1\) \(F_k=\sum_{i=0}^k s_i \sum_{j=0

P5205 【模板】多项式开根

\(\color{#0066ff}{ 题目描述 }\) 给定一个\(n-1\)次多项式\(A(x)\),求一个在\(\bmod\ x^n\)意义下的多项式\(B(x)\),使得\(B^2(x) \equiv A(x) \ (\bmod\ x^n)\) 多项式的系数在\(\bmod\ 998244353\)的意义下进行运算. \(\color{#0066ff}{输入格式}\) 第一行一个正整数\(n\). 接下来\(n\)个整数,依次表示多项式的系数\(a_0, a_1, \dots, a_{n-

cf438E. The Child and Binary Tree(NTT 多项式开根 多项式求逆)

题意 链接 Sol 生成函数博大精深Orz 我们设\(f(i)\)表示权值为\(i\)的二叉树数量,转移的时候可以枚举一下根节点 \(f(n) = \sum_{w \in C_1 \dots C_n} \sum_{j=0}^{n-w} f(j) f(n-w-j)\) 设\(T =n-w\),后半部分变为\(\sum_{j=0}^T f(j) f(T-j)\),是个标准的卷积形式. 对于第一重循环我们可以设出现过的数的生成函数\(C(x)\) 可以得到\(f = C * f * f + 1\),+

BZOJ 3625 多项式求逆+多项式开根

思路: RT //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=1<<18,mod=998244353; int A[N],C[N],invC[N],c[N],d[N],R[N],tmp[N],xx,len,sqrA[N],F[N]; typedef long long ll; int power(ll x,int y){ ll res=1; while(y){ if(y&1)r

【模板】多项式开根

懒惰的我直接指对函数搞了 #include<cstdio> #include<algorithm> #include<iostream> const int maxn = 1 << 19; const int mod = 998244353,g=3; typedef long long ll; inline int pw(int a,int b,int ans=1){ for(;b;b>>=1,a=ll(a)*a%mod) if(b&1)

【知识总结】多项式全家桶(四)(快速幂和开根)

上一篇:[知识总结]多项式全家桶(三)(任意模数NTT) 推荐小恐龙的博客(参考资料):多项式开根 (本文中一切多项式运算默认在模 \(x_n\) 意义下进行) 一.快速幂 多项式快速幂?首先有一种很显然的方式是把整数快速幂里面的整数乘法替换成多项式乘法 NTT ,复杂度 \(O(n\log^2n)\) . 然而还有一种 \(O(n\log n)\) 的做法:要求 \(B=A^k\) ,相当于求 \(\log_A B=k\) ,用换底公式得 \(\log_A B=\frac{\ln B}{\ln

[拉格朗日反演][FFT][NTT][多项式大全]详解

1.多项式的两种表示法 1.系数表示法 我们最常用的多项式表示法就是系数表示法,一个次数界为\(n\)的多项式\(S(x)\)可以用一个向量\(s=(s_0,s_1,s_2,\cdots,s_n-1)\)系数表示如下:\[S(x)=\sum_{k=0}^{n-1}s_kx^k\] 系数表示法很适合做加法,可以在\(O(n)\)的时间复杂度内完成,表达式为:\[S(x)=A(x)+B(x)=\sum_{k=0}^{n-1}(a_k+b_k)x^k\] 当中\[s_k=a_k+b_k\] 但是,系数

多项式求逆 学习总结

感觉蒟蒻现在学多项式求逆貌似有些晚了 不过真的很有意思了(然而省选的时候自己还在玩泥巴什么也不会 多项式求逆是基于倍增的 假设我们知道 h(x)f(x)=1(mod x^n) 移项得 (h(x)*f(x)-1)=0(mod x^n) 两边同时求平方得 h(x)^2*f(x)^2 - 2*h(x)*f(x) +1 = 0 (mod x^2n) 设g(x)*f(x)=1(mod x^2n) 两边同时乘以g(x)可以得 h(x)^2*f(x) -2*h(x) + g(x) =0 (mod x^2n)