codeforces #568B Symmetric and Transitive 快速傅里葉變換

題目大意:給定n ,求有多少組大小爲n 的集合上的二元關係,使其滿足對稱性、傳遞性,但不滿足自反性

一組二元關係滿足條件等價於存在一個點使其不在任何一個二元關係中

考慮將點劃分成一些集合,那麼大小爲1 的集合有兩種(有自環和沒自環),大小爲i(i>1) 的集合有一種(完全圖,且每個點上都有自環)
構造指數級生成函數C(x)=2x1!+x22!+x33!+...=ex+x1
那麼劃分方案的指數級生成函數就是eC(x)
但是這樣不對,因爲一些方案可能不包含單點
因此我們減掉不包含單點的方案數eC(x)x
答案函數爲Ans(x)=eex+x1eex1=e(ex1)(ex1)
[n]Ans(x)n! 即爲答案

然後……然後我就作死去寫了一發FFT mod any prime!
這玩應難寫得我要吐了!
4000的數據本機跑了1.7s+!1.7s+!這是O(nlogn) 啊!

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 9000
#define MOD 1000000007
using namespace std;

const int P[3]={998244353,1005060097,950009857};
const int G[3]={3,5,7};

int n,m;
long long inv[M];

void Pretreatment()
{
    int i;
    for(inv[1]=1,i=2;i<M;i++)
        inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
}

struct Int_128{
    unsigned long long a,b;
    Int_128(long long x)
    {
        a=0,b=x;
    }
    friend bool operator < (Int_128 x,Int_128 y)
    {
        return x.a < y.a || x.a == y.a && x.b < y.b ;
    }
    friend Int_128 operator + (Int_128 x,Int_128 y)
    {
        Int_128 re(0);
        re.a=x.a+y.a+(x.b+y.b<x.b);
        re.b=x.b+y.b;
        return re;
    }
    friend Int_128 operator - (Int_128 x,Int_128 y)
    {
        y.a=~y.a;y.b=~y.b;
        return x+y+1;
    }
    void Div2()
    {
        b>>=1;b|=(a&1ll)<<63;a>>=1;
    }
    friend Int_128 operator * (Int_128 x,Int_128 y)
    {
        Int_128 re=0;
        while(y.a || y.b)
        {
            if(y.b&1) re=re+x;
            x=x+x; y.Div2();
        }
        return re;
    }
    friend Int_128 operator % (Int_128 x,Int_128 y)
    {
        Int_128 temp=y;
        int cnt=0;
        while(temp<x)
            temp=temp+temp,++cnt;
        for(;cnt>=0;cnt--)
        {
            if(temp<x)
                x=x-temp;
            temp.Div2();
        }
        return x;
    }
};

long long Quick_Power(long long x,int y,int P)
{
    long long re=1;
    while(y)
    {
        if(y&1) (re*=x)%=P;
        (x*=x)%=P; y>>=1;
    }
    return re;
}

void FFT(int a[],int n,int type,int P,int G)
{
    static int rev_bit[M];
    int i,j,k,bit;
    long long w,wn;
    for(bit=0;(1<<bit)!=n;bit++);
    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)(P-1)/k*type%(P-1),P),j=0;j<n;j+=k)
            for(w=1,i=0;i<k>>1;i++,(w*=wn)%=P)
            {
                long long temp1=a[i+j],temp2=a[i+j+(k>>1)];
                a[i+j]=(temp1+w*temp2)%P;
                a[i+j+(k>>1)]=(temp1-w*temp2%P+P)%P;
            }
    if(type!=1)
    {
        long long inv=Quick_Power(n,P-2,P);
        for(i=0;i<n;i++)
            a[i]=inv*a[i]%P;
    }
}

void Polynomial_Multiplication(int a[],int b[],int c[],int n)
{
    static int A[3][M],B[3][M];
    static const long long Inv[3]={644348675,675933219,647895261};
    int i,j;
    for(j=0;j<3;j++)
    {
        for(i=0;i<n;i++)
        {
            A[j][i]=a[i]%P[j];
            B[j][i]=b[i]%P[j];
        }
        FFT(A[j],n,1,P[j],G[j]);
        FFT(B[j],n,1,P[j],G[j]);
        for(i=0;i<n;i++)
            A[j][i]=(long long)A[j][i]*B[j][i]%P[j];
        FFT(A[j],n,P[j]-2,P[j],G[j]);
    }
    Int_128 _MOD=Int_128((long long)P[0]*P[1])*P[2];
    for(i=0;i<n;i++)
    {
        Int_128 temp=
        Int_128((long long)P[1]*P[2])*Int_128(Inv[0]*A[0][i])+
        Int_128((long long)P[0]*P[2])*Int_128(Inv[1]*A[1][i])+
        Int_128((long long)P[0]*P[1])*Int_128(Inv[2]*A[2][i]);
        c[i]=(temp%_MOD%MOD).b;
    }
}

void Get_Inv(int a[],int b[],int n)
{
    static int temp[M];
    int i;
    if(n==1)
    {
        b[0]=Quick_Power(a[0],MOD-2,MOD);
        return ;
    }
    Get_Inv(a,b,n>>1);
    memcpy(temp,a,sizeof(a[0])*n);
    memset(temp+n,0,sizeof(a[0])*n);
    Polynomial_Multiplication(temp,b,temp,n<<1);
    memset(temp+n,0,sizeof(a[0])*n);
    for(i=0;i<n;i++)
        temp[i]=(MOD-temp[i])%MOD;
    (temp[0]+=2)%=MOD;
    Polynomial_Multiplication(temp,b,b,n<<1);
    memset(b+n,0,sizeof(a[0])*n);
}

void Get_Ln(int a[],int b[],int n)
{
    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;
    Polynomial_Multiplication(a_,a_inv,b,n<<1);
    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)
{
    static int temp[M];
    int i;
    if(n==1)
    {
        b[0]=1;
        return ;
    }
    Get_Exp(a,b,n>>1);
    memset(temp,0,sizeof(temp[0])*n<<1);
    Get_Ln(b,temp,n);
    for(i=0;i<n;i++)
        temp[i]=((i==0)+MOD-temp[i]+a[i])%MOD;
    Polynomial_Multiplication(b,temp,b,n<<1);
    memset(b+n,0,sizeof(b[0])*n);
}

int main()
{
    static int A[M],B[M],C[M];
    int i;

    cin>>n;

    Pretreatment();
    for(m=1;m<=n;m<<=1);
    for(A[1]=1,i=2;i<m;i++)
        A[i]=(long long)A[i-1]*inv[i]%MOD;
    Get_Exp(A,B,m);
    Polynomial_Multiplication(A,B,C,m<<1);
    long long ans=C[n];
    for(i=1;i<=n;i++)
        (ans*=i)%=MOD;
    cout<<ans<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章