UOJ#50 【UR#3C】鏈式反應 FFT求解多項式線性常微分方程

題目大意:給定n 和集合C ,對於i=1..n 求多少i 個節點有標號的多叉樹滿足:
1.父親節點的標號大於子節點
2.一個點如果有兒子,則有兩個無序的α 型兒子,有c 個無序的β 型兒子,其中cC
3.如果一個點是根節點或α 型兒子,那麼它可以有兒子或者是一個葉節點;如果一個點是β 型兒子,那麼它只能是一個葉節點

由於有標號,所以這裏顯然要使用指數級生成函數
fi 表示i 個節點的多叉數數量,其指數級生成函數爲:
F(x)=fixii!
那麼考慮:
根節點是固定的,不參與標號的排列,首先把根節點刨掉,即:
F(x)=fixi1(i1)!
然後一棵樹可能只有一個葉節點,刨掉之後就什麼都不剩了;
也可能有兒子,這時候兒子分爲三部分:
α1,α2,β ,三者的指數級生成函數分別爲F(x),F(x),C(x)
故直觀上來看應該是F2(x)C(x) ,但是這樣不對,因爲α1α2 沒有順序,所以應該是12F2(x)C(x)
可以列出方程:
F(x)=12F2(x)C(x)+1

這個方程怎麼解?

牛頓迭代。

假設現在我們有待定多項式x(t) 、常多項式a(t) 、已知函數f(x)=12ax2+1 ,求解方程:
ddtx=f(x)
老辦法,倍增處理。
假設我們已經知道了x(t) 的前nxn ,求x(t) 的前2nx2n
泰勒展開:
ddtx2n=f(x2n)=f(xn)+f(xn)(x2nxn)+f′′(xn)(x2xxn)2+...
ddtx2n=f(xn)+f(xn)(x2nxn) (mod t2n)
ddtx2nx2nf(xn)=f(xn)xnf(xn) (mod t2n)
看到這裏學過微積分的人已經會構造了吧。
r=ef(xn)dt ,則ddtr=f(xn)r
等式兩邊同乘r 得到:
rddtx2n+x2nddtr=(f(xn)xnf(xn))r (mod t2n)
ddt(x2nr)=(f(xn)xnf(xn))r (mod t2n)
x2n=(f(xn)xnf(xn))r dtr (mod t2n)
x2n=(112ax2n)r dtr (mod t2n)
裏面的一切計算都是O(nlogn) 的,總時間複雜度T(n)=O(nlogn)+T(n2)=O(nlogn)
注意常數……

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 530000
#define MOD 998244353
#define G 3
using namespace std;
int n,m,d;
long long inv[M];
int A[M],B[M];
void Linear_Shaker()
{
    int i;
    for(inv[1]=1,i=2;i<=d<<1;i++)
        inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
}
long long Quick_Power(long long x,int y)
{
    long long re=1;
    while(y)
    {
        if(y&1) (re*=x)%=MOD;
        (x*=x)%=MOD; y>>=1;
    }
    return re;
}
void FFT(int a[],int n,int type){
    static int rev_bit[M];
    int i,j,k,w,wn,t,bit;
    for(bit=0;1<<bit<n;++bit);
    static int b[M];
    for(i=0;i<n;i++)
        rev_bit[i]=(rev_bit[i>>1]>>1)|((i&1)<<bit-1);
    for(i=0;i<n;i++)
        if(i<rev_bit[i])
            swap(a[i],a[rev_bit[i]]);
    for(k=2;k<=n;k<<=1)
        for(wn=Quick_Power(G,(long long)(MOD-1)/k*type%(MOD-1)),i=0;i<n;i+=k)
            for(w=1,j=0;j<k>>1;++j,w=(long long)w*wn%MOD)
            {
                t=(long long)w*a[i+j+(k>>1)]%MOD;
                a[i+j+(k>>1)]=a[i+j]-t<0?a[i+j]-t+MOD:a[i+j]-t;
                a[i+j]=a[i+j]+t>=MOD?a[i+j]+t-MOD:a[i+j]+t;
            }
    if(type!=1)
    {
        for(i=0;i<n;i++)
            a[i]=(long long)a[i]*inv[n]%MOD;
    }
}
void Get_Inv(int a[],int b[],int n) 
//求a的逆,長度爲n,結果儲存在b中。
//要求傳入時b[0...n<<1]爲空。
{
    static int temp[M];
    int i;
    if(n==1)
    {
        b[0]=Quick_Power(a[0],MOD-2);
        return ;
    }
    Get_Inv(a,b,n>>1);
    memcpy(temp,a,sizeof(a[0])*n);
    memset(temp+n,0,sizeof(a[0])*n);
    FFT(temp,n<<1,1);
    FFT(b,n<<1,1);
    for(i=0;i<n<<1;i++)
        temp[i]=(long long)b[i]*(2-(long long)temp[i]*b[i]%MOD+MOD)%MOD;
    FFT(temp,n<<1,MOD-2);
    memcpy(b,temp,sizeof(a[0])*n);
    memset(b+n,0,sizeof(a[0])*n);
}
void Get_Ln(int a[],int b[],int n)
//求a的ln,長度爲n,結果儲存在b中。
//要求a的常數項爲1。
{
    static int a_[M],a_inv[M];
    int i;
    Get_Inv(a,a_inv,n);
    for(i=0;i<n-1;i++)
        a_[i]=(long long)a[i+1]*(i+1)%MOD;
    FFT(a_,n<<1,1);
    FFT(a_inv,n<<1,1);
    for(i=0;i<n<<1;i++)
        b[i]=(long long)a_[i]*a_inv[i]%MOD;
    FFT(b,n<<1,MOD-2);
    for(i=n-1;i;i--)
        b[i]=b[i-1]*inv[i]%MOD;
    b[0]=0;
    memset(b+n,0,sizeof(b[0])*n);
    memset(a_,0,sizeof(a_[0])*n<<1);
    memset(a_inv,0,sizeof(a_inv[0])*n<<1);
}
void Get_Exp(int a[],int b[],int n)
//求a的exp,長度爲n,結果儲存在b中。
//要求傳入時b[0...n<<1]爲空。
//要求a的常數項爲0。
{
    static int temp[M];
    int i;
    if(n==1)
    {
        b[0]=1;
        return ;
    }
    Get_Exp(a,b,n>>1);
    Get_Ln(b,temp,n);
    for(i=0;i<n;i++)
        temp[i]=((i==0)+MOD-temp[i]+a[i])%MOD;
    FFT(temp,n<<1,1);
    FFT(b,n<<1,1);
    for(i=0;i<n<<1;i++)
        b[i]=(long long)b[i]*temp[i]%MOD;
    FFT(b,n<<1,MOD-2);
    memset(b+n,0,sizeof(b[0])*n);
}
void Newton_Method(int a[],int b[],int n)
//求解常微分方程dx/dt=ax^2/2+1,長度爲n,結果儲存在b中。
//要求傳入時b[0...n<<1]爲空。
//x[2n]=int( (1-ax^2/2)*r )/r
//r=exp(-int(ax))
{
    static int temp[M],temp_temp[M],r[M],r_temp[M];
    int i;
    if(n==1)
    {
        b[0]=0;
        return ;
    }
    Newton_Method(a,b,n>>1);
    memcpy(temp,a,sizeof(a[0])*n);
    memset(temp+n,0,sizeof(a[0])*n);
    FFT(temp,n<<1,1);
    FFT(b,n<<1,1);
    for(i=0;i<n<<1;i++)
        temp_temp[i]=(long long)temp[i]*b[i]%MOD;
    FFT(temp_temp,n<<1,MOD-2);
    for(i=n-1;i;i--)
        temp_temp[i]=temp_temp[i-1]*inv[i]%MOD*(MOD-1)%MOD;
    temp_temp[0]=0;
    memset(r,0,sizeof(a[0])*n<<1);
    Get_Exp(temp_temp,r,n);

    for(int i=0;i<n<<1;i++)
        temp[i]=(1+inv[2]*(MOD-1)%MOD*temp[i]%MOD*b[i]%MOD*b[i]%MOD)%MOD;
    FFT(temp,n<<1,MOD-2);
    memset(temp+n,0,sizeof(a[0])*n);

    memcpy(r_temp,r,sizeof(a[0])*n<<1);
    FFT(temp,n<<1,1);
    FFT(r_temp,n<<1,1);
    for(int i=0;i<n<<1;i++)
        temp[i]=(long long)temp[i]*r_temp[i]%MOD;
    FFT(temp,n<<1,MOD-2);

    for(i=n-1;i;i--)
        temp[i]=temp[i-1]*inv[i]%MOD;
    temp[0]=0;
    memset(temp+n,0,sizeof(a[0])*n);

    memset(r_temp,0,sizeof(a[0])*n<<1);
    Get_Inv(r,r_temp,n);

    FFT(temp,n<<1,1);
    FFT(r_temp,n<<1,1);
    for(int i=0;i<n<<1;i++)
        b[i]=(long long)temp[i]*r_temp[i]%MOD;
    FFT(b,n<<1,MOD-2);

    memset(b+n,0,sizeof(a[0])*n);
    memset(temp+n,0,sizeof(a[0])*n);
}
int main()
{
    cin>>n;
    for(d=1;d<=n+1;d<<=1);
    Linear_Shaker();

    long long temp=1;
    for(int i=0;i<n;i++)
    {
        scanf("%1d",&A[i]);
        A[i]=A[i]*temp;
        (temp*=inv[i+1])%=MOD;
    }

    Newton_Method(A,B,d);

    temp=1;
    for(int i=1;i<=n;i++)
    {
        (temp*=i)%=MOD;
        printf("%d\n",int(B[i]*temp%MOD));
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章