zoukankan      html  css  js  c++  java
  • 【BZOJ3625/CF438E】小朋友和二叉树(多项式求逆,多项式开方)

    【BZOJ3625/CF438E】小朋友和二叉树(多项式求逆,多项式开方)

    题面

    BZOJ
    CodeForces
    大致题意:
    对于每个数出现的次数对应的多项式(A(x))
    求$$f(x)=frac{2}{sqrt{-4A(x)+1}+1}$$

    题解

    多项式开方+多项式求逆模板题
    我之前写的多项式求逆很丑,常数大的惊人
    成功拿到洛谷模板题倒数第一的速度

    于是,我学习了一波Gay神的写法
    写了一下这道题目

    具体的细节暂时不写了,以后肯定有机会的写的(这点我可以保证)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 500000
    #define MOD 998244353
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int n,m,inv2,d[MAX];
    int fpow(int a,int b)
    {
    	int s=1;
    	while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
    	return s;
    }
    namespace NTT
    {
    	int r[MAX],N,M,l;
    	int A[MAX],B[MAX];
    	void NTT(int *P,int n,int opt)
    	{
    		int N=1,l=0;for(N=1;N<n;N<<=1)++l;
    		for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    		for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
    		for(int i=1;i<N;i<<=1)
    		{
    			int W=fpow(3,(MOD-1)/(i<<1));
    			for(int p=i<<1,j=0;j<N;j+=p)
    			{
    				int w=1;
    				for(int k=0;k<i;++k,w=1ll*w*W%MOD)
    				{
    					int X=P[j+k],Y=P[i+j+k]*1ll*w%MOD;
    					P[j+k]=(X+Y)%MOD;P[i+j+k]=(X-Y+MOD)%MOD;
    				}
    			}
    		}
    		if(opt==-1)
    		{
    			reverse(&P[1],&P[N]);
    			for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
    		}
    	}
    }
    int b[MAX];
    int A[MAX],B[MAX],C[MAX],D[MAX],c[MAX];
    void Inv(int *a,int *b,int len)
    {
    	if(len==1){b[0]=fpow(a[0],MOD-2);return;}
    	Inv(a,b,len>>1);
    	for(int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
    	NTT::NTT(A,len<<1,1);NTT::NTT(B,len<<1,1);
    	for(int i=0;i<(len<<1);++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;
    	NTT::NTT(A,len<<1,-1);
    	for(int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;
    	for(int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;
    	for(int i=0;i<(len<<1);++i)A[i]=B[i]=0;
    }
    void Sqrt(int *a,int *b,int len)
    {
    	if(len==1){b[0]=a[0];return;}
    	Sqrt(a,b,len>>1);
    	for(int i=0;i<=len;++i)C[i]=a[i];
    	Inv(b,D,len);
    	NTT::NTT(C,len<<1,1);NTT::NTT(D,len<<1,1);
    	for(int i=0;i<(len<<1);++i)D[i]=1ll*D[i]*C[i]%MOD;
    	NTT::NTT(D,len<<1,-1);
    	for(int i=0;i<len;++i)b[i]=1ll*(D[i]+b[i])%MOD*inv2%MOD;
    	for(int i=0;i<=(len<<1);++i)C[i]=D[i]=0;
    }
    int main()
    {
    	n=read();m=read();inv2=fpow(2,MOD-2);
    	for(int i=1;i<=n;++i)++d[read()];
    	int N=1;while(N<=m)N<<=1;
    	for(int i=0;i<N;++i)d[i]=(-4*d[i]+MOD)%MOD;
    	++d[0];
    	Sqrt(d,c,N);
    	for(int i=0;i<N;++i)d[i]=0;
    	c[0]=(c[0]+1)%MOD;
    	Inv(c,d,N);
    	for(int i=0;i<=m;++i)d[i]=(d[i]+d[i])%MOD;
    	for(int i=1;i<=m;++i)printf("%d
    ",d[i]);
    	return 0;
    	
    }
    
    
  • 相关阅读:
    算法导论6.33习题解答
    最短子序列(最短摘要)
    算法导论83(b)习题解答(trie树)
    算法导论61习题解答
    算法导论8.24习题解答(计数排序)
    算法导论8.34习题解答(基数排序)
    算法导论6.57习题解答
    算法导论63习题解答(Young氏矩阵)
    算法导论6.58习题解答(最小堆K路合并)
    算法导论6.17习题解答
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8646537.html
Copyright © 2011-2022 走看看