zoukankan      html  css  js  c++  java
  • 多项式乘法逆

    P4238 【模板】多项式乘法逆

    给定一个多项式 (F(x)) ,请求出一个多项式 (G(x)), 满足 (F(x) * G(x) equiv 1 ( mathrm{mod:} x^n ))。系数对 (998244353) 取模。

    考虑倍增

    多项式只有一项时就是乘法逆元

    假设我们现在得到了

    [G^{'}(x) equiv F(x) (mod x^{frac{n}{2}}) ]

    我们需要求

    [G(x)equiv F(x) (mod x^n) ]

    很明显

    [G(x)-G^{'}(x)equiv 0 (mod x^{frac{n}{2}}) ]

    两边同时平方

    [G(x)^2-2*G(x)G^{'}(x)+G^{'}(x)equiv 0 (mod x^n) ]

    两边同时乘(F(x))得到

    [F(x)(G(x)^2-2*G(x)G^{'}(x)+G^{'}(x))equiv 0 (mod x^n) ]

    由于

    [F(x)G(x)equiv 1(mod x^n) ]

    所以

    [G(x)-2G(x)^{'}+F(x)G^{'2}(x)equiv (mod x^n) ]

    移下项

    [G(x)equiv 2G(x)^{'}-F(x)G^{'2}(x)(mod x^n) ]

    只要初始设置(G(0)=F(0)^{-1})就可以倍增啦~

    额额额不知道有没有人和我有一样的疑惑:为啥递归一次多项式次数少一半,原因是模掉了……

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define eps (1e-8)
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=5e5+10,p=998244353,g=3,gi=332748118;
    	int n;
    	int a[N],b[N],c[N];
    	int pos[N];
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	inline void ntt(int limit,int *a,int inv)
    	{
    		for(int i=0;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(g,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=x+y;
    					if(a[j+k]>=p) a[j+k]-=p;
    					a[j+k+mid]=x-y;
    					if(a[j+k+mid]<0) a[j+k+mid]+=p;
    				}
    			}
    		}
    		if(inv) return;
    		inv=fast(limit,p-2);reverse(a+1,a+limit);
    		for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
    	}
    	inline void poly_inv(int pw,int *a,int *b)
    	{
    		if(pw==1) {b[0]=fast(a[0],p-2);return;}
    		poly_inv((pw+1)>>1,a,b);
    		int len=0,limit=1;
    		while(limit<(pw<<1)) limit<<=1,++len;
    		for(int i=1;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		for(int i=0;i<pw;++i) c[i]=a[i];
    		for(int i=pw;i<limit;++i) c[i]=0;
    		ntt(limit,c,1);ntt(limit,b,1);
    		for(int i=0;i<limit;++i) b[i]=((2-c[i]*b[i]%p)+p)%p*b[i]%p;
    		ntt(limit,b,0);
    		for(int i=pw;i<limit;++i) b[i]=0;
    	}
    	inline void main()
    	{
    		n=read();
    		for(int i=0;i<n;++i) a[i]=read();
    		poly_inv(n,a,b);
    		for(int i=0;i<n;++i) printf("%lld ",b[i]);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    LeetCode--Reorder List
    LeetCode--Combination Sum
    LeetCode--Binary Tree Level Order Traversal
    LeetCode--Plus One
    第五届蓝桥杯决赛CC++B组——生物芯片
    第五届蓝桥杯决赛CC++B组——Log大侠
    第五届蓝桥杯决赛CC++B组——出栈次序
    1098 均分纸牌 ——http://codevs.cn/problem/1098/
    1294 全排列——http://codevs.cn/problem/1294/
    1501 二叉树最大宽度和高度——http://codevs.cn/problem/1501/
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12055371.html
Copyright © 2011-2022 走看看