码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3625][Codeforces Round #250]小朋友和二叉树

时间:2018-02-10 12:49:44      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:post   define   没有   names   des   return   play   long   end   

[bzoj3625][Codeforces Round #250]小朋友和二叉树

标签: 多项式开方 多项式求逆


Description

一棵树的所有点的点权都是给定的集合C中的一个数。
让你求出1到m中所有权值为i的树的个数。
两棵树不同当且仅当树的形态不一样或者是树的某个点的点权不一样
\(998244353\)取模
\(n,m<=10^5\)

(jiade)Solution

递推式应该挺好写的。
\(c(i)\)表示i是否在集合C中。
\[f(n)=\sum_{i=1}^n c(i)\sum _{j=0}^{n-i}f(j)f(n-i-j)\]
特别的,\(f(0)=1\)

然后把\(f(i)\)提出来。
\[f(n)=\sum_{i=0}^{n-1}f(i)\sum _{j=0}^{n-i}f(j)c(n-i-j)\]
可以注意到这是一个卷积套卷积的形式。

\(g(n)=\sum_{j=0}^nf(i)c(n-i)\)
那么\[f(n)=\sum_{j=0}^{n-1}f(i)×g(n-i)\]

cdq+NTT即可。














Real Solution

应该没有人会信我的鬼话吧
其实我一开始是这么写的
在cdq分治的时候,首先会求出[l,mid]内的\(f(i)\)
然后再与[1,r-l+1]中的\(g(i)\)做卷积。
可是当l=1时,有些\(g(i)\)是还没有求出来的。
所以卷积个鬼啊。

我们设生成函数\(F(i)=\sum_{i=0}^n f(i)x^i\),\(C(i)=\sum _{i=1}c(i)x^i\)
那么有\(F(x)=F(x)^2C(x)+1\)
解得\[F(x)={1+(-) {\sqrt {1-4C(x)}} \over 2C(x)}\]
\[F(x)={2 \over {1-(+)\sqrt {1-4C(x)}}}\]
显然符号是取\(+\)号的。
因为当\(x=0\)如果取\(-\)号那么分母为0没有意义。

所以\[F(x)={2 \over {1+\sqrt {1-4C(x)}}}\]
多项式开方和多项式求逆即可。

Code

给一份假的代码。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
    int sum=0,p=1;char ch=getchar();
    while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    if(ch=='-')p=-1,ch=getchar();
    while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    return sum*p;
}

const int mod=998244353;
const int maxn=4e5+20;

int n,m,f[maxn],g[maxn],ok[maxn],rev[maxn],A[maxn],B[maxn];

inline int power(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b & 1)ans=(ll)ans*a%mod;
        b>>=1;
        a=(ll)a*a%mod;
    }
    return ans;
}

inline void init()
{
    m=read();n=read();
    REP(i,1,m)ok[read()]=1;
    ok[0]=1;
}

inline void NTT(int *p,int n,int op)
{
    REP(i,0,n-1)if(i<rev[i])swap(p[i],p[rev[i]]);
    for(int i=1;i<n;i<<=1)
    {
        int W=power(3,(mod-1)/(i<<1));
        for(int j=0;j<n;j+=i<<1)
        {
            int w=1;
            for(int k=j;k<i+j;k++,w=(ll)W*w%mod)
            {
                int x=p[k],y=(ll)p[k+i]*w%mod;
                p[k]=x+y;p[k+i]=x-y;
                if(p[k]>=mod)p[k]-=mod;
                if(p[k+i]<0)p[k+i]+=mod;
            }
        }
    }
    if(op==-1)
    {
        int inv=power(n,mod-2);
        REP(i,0,n-1)p[i]=(ll)p[i]*inv%mod;
        reverse(p+1,p+n);
    }
}

void solve(int l,int r)
{
    if(l==r){g[l]=(g[l]+ok[l])%mod;f[l]=(f[l]+g[l])%mod;return;}
    int mid=(l+r)>>1;
    solve(l,mid);
    int N=1,L=0;
    while(N<=2*(mid-l+1))N<<=1,L++;
    REP(i,1,N-1)rev[i]=(rev[i>>1]>>1)|(1<<(L-1));
    /*--- get f(i) ---*/
    REP(i,0,N-1)A[i]=B[i]=0;
    REP(i,0,mid-l)A[i]=f[i+l];REP(i,1,mid-l+1)B[i]=g[i];
    NTT(A,N,1);NTT(B,N,1);
    REP(i,0,N-1)A[i]=(ll)A[i]*B[i]%mod;
    NTT(A,N,-1);
    REP(i,mid-l+1,r-l)f[i+l]=(f[i+l]+A[i])%mod;
    
    /*--- get g(i) ---*/
    REP(i,0,N-1)A[i]=B[i]=0;
    REP(i,0,mid-l)A[i]=f[i+l];REP(i,1,mid-l+1)B[i]=ok[i];
    NTT(A,N,1);NTT(B,N,1);
    REP(i,0,N-1)A[i]=(ll)A[i]*B[i]%mod;
    NTT(A,N,-1);
    REP(i,mid-l+1,r-l)g[i+l]=(g[i+l]+A[i])%mod;
    solve(mid+1,r);
}

inline void doing()
{
    f[0]=g[0]=1;
    solve(1,n);
    REP(i,1,n)printf("%d\n",f[i]);
}

int main()
{
    init();
    doing();
    return 0;
}

正确代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
    int sum=0,p=1;char ch=getchar();
    while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    if(ch=='-')p=-1,ch=getchar();
    while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    return sum*p;
}

const int maxn=4e5+20;
const int mod=998244353;
const int inv2=(mod+1)/2;

int n,c[maxn],m,rev[maxn];

inline int power(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b & 1)ans=(ll)ans*a%mod;
        b>>=1;
        a=(ll)a*a%mod;
    }
    return ans;
}

inline void NTT(int *p,int N,int op)
{
    int n=1,l=0;while(n<N)n<<=1,l++;
    REP(i,1,n-1)rev[i]=(rev[i>>1]>>1)|((i & 1)<<(l-1));
    REP(i,0,n-1)if(i<rev[i])swap(p[i],p[rev[i]]);
    for(int i=1;i<n;i<<=1)
    {
        int W=power(3,(mod-1)/(i<<1));
        for(int j=0;j<n;j+=i<<1)
        {
            int w=1;
            for(int k=j;k<i+j;k++,w=(ll)w*W%mod)
            {
                int x=p[k],y=(ll)p[k+i]*w%mod;
                p[k]=x+y;p[k+i]=x-y;
                if(p[k]>mod)p[k]-=mod;
                if(p[k+i]<0)p[k+i]+=mod;
            }
        }
    }
    if(op==-1)
    {
        int inv=power(n,mod-2);
        REP(i,0,n-1)p[i]=(ll)p[i]*inv%mod;
        reverse(p+1,p+n);
    }
}

int A[maxn],B[maxn],C[maxn];

int tmp[maxn];

void Inv(int *p,int *q,int len)
{
    if(len==1)
    {
        q[0]=power(p[0],mod-2);
        return;
    }
    Inv(p,q,len>>1);
    REP(i,0,len-1)A[i]=p[i],B[i]=q[i];
    NTT(A,len<<1,1);NTT(B,len<<1,1);
    REP(i,0,(len<<1)-1)A[i]=(ll)B[i]*B[i]%mod*A[i]%mod;
    NTT(A,len<<1,-1);
    REP(i,0,len-1)q[i]=((-A[i]+2*q[i])%mod+mod)%mod;
    REP(i,0,len<<1)A[i]=B[i]=0;
}

void Sqrt(int *p,int *q,int len)
{
    if(len==1)
    {
        q[0]=p[0];
        return;
    }
    Sqrt(p,q,len>>1);
    REP(i,0,len)C[i]=p[i];
    Inv(q,tmp,len);
    NTT(tmp,len<<1,1);NTT(C,len<<1,1);
    REP(i,0,(len<<1)-1)tmp[i]=(ll)tmp[i]*C[i]%mod;
    NTT(tmp,len<<1,-1);
    REP(i,0,len-1)q[i]=(ll)(tmp[i]+q[i])*inv2%mod;
    REP(i,0,len<<1)C[i]=tmp[i]=0;
}

void init()
{
    m=read();n=read();
    REP(i,1,m)c[read()]=1;
}

int d[maxn];

void doing()
{
    int N=1,l=0;while(N<=n)N<<=1,l++;
    REP(i,0,N-1)c[i]=(-4*c[i]+mod)%mod;
    c[0]++;
    Sqrt(c,d,N);
    REP(i,0,N-1)c[i]=0;
    d[0]=(d[0]+1)%mod;
    Inv(d,c,N);
    REP(i,0,N-1)c[i]=c[i]*2%mod;
    REP(i,1,n)printf("%d\n",c[i]);
}

int main()
{
    init();
    doing();
    return 0;
}

[bzoj3625][Codeforces Round #250]小朋友和二叉树

标签:post   define   没有   names   des   return   play   long   end   

原文地址:https://www.cnblogs.com/gzy-cjoier/p/8438225.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!