• 【洛谷P4238】【模板】多项式乘法逆


    题目

    题目链接:https://www.luogu.com.cn/problem/P4238
    给定一个多项式 (F(x)) ,请求出一个多项式 (G(x)), 满足 (F(x) * G(x) equiv 1 ( mathrm{mod:} x^n ))。系数对 (998244353) 取模。
    (nleq 10^5)

    思路

    假设我们已经知道了 (F(x)G'(x)equiv 1pmod {x^{frac{n}{2}}}),考虑如何推广到 (F(x)G(x)equiv 1pmod {x^n})
    首先显然有

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

    两边平方后拆开

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

    同时乘上 (F(x))

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

    所以

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

    然后就可以递推了。
    (T(n)=T(frac{n}{2})+O(nlog n)),故时间复杂度为 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=300010,MOD=998244353,G=3,Ginv=332748118;
    int n,rev[N];
    ll f[N],g[2][N],h[N],X[N],Y[N];
    
    ll fpow(ll x,ll k)
    {
    	ll ans=1;
    	for (;k;k>>=1,x=x*x%MOD)
    		if (k&1) ans=ans*x%MOD;
    	return ans;
    }
    
    void NTT(ll *f,int tag,int lim)
    {
    	for (int i=0;i<lim;i++)
    		if (i<rev[i]) swap(f[i],f[rev[i]]);
    	for (int k=1;k<lim;k<<=1)
    	{
    		ll tmp=fpow((tag==1)?G:Ginv,(MOD-1)/(k<<1));
    		for (int i=0;i<lim;i+=(k<<1))
    		{
    			ll w=1;
    			for (int j=0;j<k;j++,w=w*tmp%MOD)
    			{
    				ll x=f[i+j],y=w*f[i+j+k]%MOD;
    				f[i+j]=(x+y)%MOD; f[i+j+k]=(x-y+MOD)%MOD;
    			}
    		}
    	}
    }
    
    void Fmul(ll *f,ll *g,ll lim)
    {
    	memset(X,0,sizeof(X));
    	memset(Y,0,sizeof(Y));
    	for (int i=0;i<(lim>>1);i++)
    		X[i]=f[i],Y[i]=g[i];
    	NTT(X,1,lim); NTT(Y,1,lim);
    	for (int i=0;i<lim;i++) X[i]=X[i]*Y[i]%MOD;
    	NTT(X,-1,lim);
    	ll inv=fpow(lim,MOD-2);
    	for (int i=0;i<lim;i++) X[i]=X[i]*inv%MOD;
    	memcpy(f,X,sizeof(X));
    }
    
    void Finv(ll *f)
    {
    	g[0][0]=fpow(f[0],MOD-2);
    	int id=0;
    	for (int lim=4;lim<(n<<2);lim<<=1)
    	{
    		id^=1;
    		for (int i=0;i<lim;i++)
    			rev[i]=(rev[i>>1]>>1)|((i&1)?(lim>>1):0);
    		memcpy(h,g[id^1],sizeof(h));
    		Fmul(h,g[id^1],lim); Fmul(h,f,lim);
    		for (int i=0;i<(lim>>1);i++)
    			g[id][i]=(2*g[id^1][i]-h[i]+MOD)%MOD;
    	}
    	for (int i=0;i<n;i++)
    		printf("%lld ",g[id][i]);
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=0;i<n;i++)
    		scanf("%lld",&f[i]);
    	Finv(f);
    	return 0;
    }
    
  • 相关阅读:
    BZOJ 3684 大朋友和多叉树
    Loj #2495. 「AHOI / HNOI2018」转盘
    Loj #2494. 「AHOI / HNOI2018」寻宝游戏
    Loj 2320.「清华集训 2017」生成树计数
    SQL Server 权限管理
    微信和支付宝支付模式详解及实现(.Net标准库)- OSS开源系列
    跨站请求伪造(CSRF)
    require.js入门
    C#中禁止跨线程直接访问控件
    Video.js web视频播放器
  • 原文地址:https://www.cnblogs.com/stoorz/p/14281329.html
Copyright © 2020-2023  润新知