记录编号 372715 评测结果 AAAAAAAAAA
题目名称 [BZOJ 3456] 城市规划 最终得分 100
用户昵称 Gravatarstdafx.h 是否通过 通过
代码语言 C++ 运行时间 4.104 s
提交时间 2017-02-18 22:07:42 内存使用 10.59 MiB
显示代码纯文本
/*
    G(x) = sigma ( 2^C(i,2) x ^ i / ( i! ) )
    F(x) = sigma ( fi * x ^ i / ( i! ) )
    G(x) = e ^ F(x)
    F(x) = ln ( G(x) )
*/
 
#define fastcall __attribute__((optimize("-Os")))
#define IL __inline__ __attribute__((always_inline))
 
#define maxn 270010ul
 
#define ll long long
 
#include <stdio.h>
#include <string.h>
#include <algorithm>
 
const int G=3,P=1004535809;

int R;

fastcall IL int mul_mod(int a,int b){
    __asm__ __volatile__ ("\tmull %%ebx\n\tdivl %%ecx\n" :"=d"(R):"a"(a),"b"(b),"c"(P));
    return R;
}

fastcall IL int sub(int x,int y){
    x-=y; return x<0?x+P:x;
}

namespace polynomial{
	int W[maxn];
    fastcall IL int ksm(int p,ll k){
        int ans=1;
        while(k){
            if(k&1) ans=mul_mod(ans,p);
            k>>=1ll,p=mul_mod(p,p);
        } return ans;
    }
    fastcall void ntt(int *a,int n,int flag){
        for(int i=0,j=0;i<n;i++){
            if(i>j) std::swap(a[i],a[j]);
            for(int t=n>>1;(j^=t)<t;t>>=1);
        } register int wn,u,t;
        for(register int m=2,i,k,p;m<=n;m<<=1){
            wn=ksm(G,flag==1?(P-1)/m:(P-1-(P-1)/m));
            W[0]=1; for(i=1,p=m>>1;i<p;i++) W[i]=mul_mod(W[i-1],wn);
            for(i=0;i<n;i+=m) for(k=0;k<p;k++)
                t=1ll*W[k]*a[i+k+p]%P,u=a[i+k],a[i+k]=(u+t)%P,a[i+k+p]=sub(u,t);
        }
        if(flag==-1){
            int inv=ksm(n,P-2);
            for(int i=0;i<n;i++) a[i]=1ll*a[i]*inv%P;
        } return;
    }
    void poly_derivative(int *poly,int *der,int n){
        poly[n]=0;
        for(int i=0;i<n;i++) der[i]=1ll*(i+1)*poly[i+1]%P;
        return;
    }
    void poly_integrate(int *poly,int n){
        static int tmp[maxn];
        for(int i=0;i<n;i++) tmp[i+1]=1ll*poly[i]*ksm(i+1,P-2)%P;
        for(int i=0;i<n;i++) poly[i]=tmp[i];
        return;
    }
    /*
 
    & polynomial inverse
 
    -> G(x) * F(x) = 1 ( mod x^n )
    -> H(x) * F(x) = 1 ( mod x^2n )
 
    -> we want to know -> H(x)
 
    -> G(x) * F(x) - 1 =0 ( mod x^n )
    -> [G(x) * F(x) - 1] ^ 2 = 0 ( mod x^2n )
    -> [G(x)F(x)] ^ 2 - 2 * G(x) * F(x) + 1 = 0 ( mod x^2n )
    -> G(x) ^ 2 * F(x) - 2 * G(x) + H(x) = 0 ( mod x^2n )
    -> H(x) = 2 * G(x) - G(x) ^ 2 * F(x)
 
    -> H(x) = G(x) * [ 2 - G(x) * F(x) ]
 
    */
    void poly_inverse(int *f,int *g,int n){
        static int tmp[maxn];
        if(n==1){g[0]=ksm(f[0],P-2);return;}
        poly_inverse(f,g,n>>1);
        memcpy(tmp,f,sizeof(f[0])*n);
        memset(tmp+n,0,sizeof(f[0])*n);
        ntt(tmp,n<<1,1),ntt(g,n<<1,1);
        for(int i=0;i<(n<<1);i++) tmp[i]=1ll*g[i]*(2ll-1ll*g[i]*tmp[i]%P)%P;
        ntt(tmp,n<<1,-1);
        for(int i=0;i<n;i++) g[i]=tmp[i];
        memset(g+n,0,sizeof(g[0])*n);
        return;
    }
    /*
 
    & polynomial sqrt
 
    ->   G(x) ^ 2 = F(x) ( mod x^n )
    ->   H(x) ^ 2 = F(x) ( mod x^2n )
 
    ->   we want to know -> H(x)
 
    ->   G(x) ^ 2 - F(x) = 0 ( mod x^n )
    ->   [ G(x) ^ 2 - F(x) ] ^ 2 = 0 ( mod x^2n )
    ->   [ G(x) ^ 2 + F(x) ] ^ 2 = 4 * ( G(x) ^ 2 ) * F(x) ( mod x^2n )
    ->   [ (G(x) ^ 2 + F(x)) / ( 2 * G(x) ) ] ^ 2 = F(x) ( mod x^2n )
 
    ->   H(x) = (G(x) ^ 2 + F(x)) / ( 2 * G(x) )
 
    */
    void poly_sqrt(int *f,int *g,int n){
        static int tmp[maxn],ginv[maxn];
        if(n==1){g[0]=1;return;}
        int inv2=ksm(2,P-2);
        poly_sqrt(f,g,n>>1);
        memset(ginv,0,sizeof(ginv[0])*n);
        poly_inverse(g,ginv,n);
        memcpy(tmp,f,sizeof(f[0])*n);
        memset(tmp+n,0,sizeof(f[0])*n);
        ntt(tmp,n<<1,1),ntt(g,n<<1,1),ntt(ginv,n<<1,1);
        for(int i=0;i<(n<<1);i++) tmp[i]=1ll*inv2*(g[i]+1ll*tmp[i]*ginv[i]%P)%P;
        ntt(tmp,n<<1,-1);
        for(int i=0;i<n;i++) g[i]=tmp[i];
        memset(g+n,0,sizeof(g[0])*n);
        return;
    }
    /*
 
    & polynomial ln
    ->   F(x) = ln ( G(x) )
    ->   F'(x) = G'(x) / G(x)
 
    ->   F(x) = ∫( G'(x) / G(x) ) dx
 
    */
    void poly_ln(int *poly,int *ln,int n){
        static int der[maxn],inv[maxn];
        memset(inv,0,sizeof(inv));
        poly_inverse(poly,inv,n);
        poly_derivative(poly,der,n);
        ntt(der,n<<1,1),ntt(inv,n<<1,1);
        for(int i=0;i<(n<<1);i++)
            ln[i]=1ll*der[i]*inv[i]%P;
        ntt(ln,n<<1,-1);
        memset(ln+n,0,sizeof(ln[0])*n);
        poly_integrate(ln,n);
        return;
    }
};
 
int n,m,g[maxn],f[maxn],fac[maxn];
 
inline ll C(ll i,ll j=2){
    return i*(i-1)>>1ll;
}
 
int main(){
	freopen("bzoj_3456.in","r",stdin);
	freopen("bzoj_3456.out","w",stdout);
    scanf("%d",&n);
    for(m=1;m<=(n<<1);m<<=1); m>>=1; 
    fac[0]=1;for(int i=1;i<m;i++) fac[i]=1ll*fac[i-1]*i%P;
    for(int i=0;i<m;i++) g[i]=1ll*polynomial::ksm(2,C(i,2))*polynomial::ksm(fac[i],P-2)%P;
    polynomial::poly_ln(g,f,m);
    f[n]=1ll*f[n]*fac[n]%P,(f[n]+=P)%=P,printf("%d",f[n]);
    return 0;
}