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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章