BZOJ 3456: 城市规划 多项式求逆

BZOJ 3456: 城市规划 多项式求逆

Code:

#include <bits/stdc++.h>
#define N 3333300
#define mod 1004535809 
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
#define shut fclose(stdin),fclose(stdout) 
using namespace std;
int qpow(int x,int y)
{
    int tmp = 1;
    while(y)
    {
        if(y&1) tmp=1ll*tmp*x%mod; 
        x=1ll*x*x%mod,y>>=1; 
    }
    return tmp; 
}
namespace NTT
{
    int a[N],b[N],f[N],g[N]; 
    void NTT(int *a,int len,int opt){ 
        for(int i = 0,k = 0;i < len; ++i)
        {
            if(i > k) swap(a[i],a[k]); 
            for(int j = len >> 1;(k^=j)<j;j>>=1); 
        }
        for(int k = 2;k <= len;k <<= 1)
        {
            int t = (k>>1),x=qpow(3,(mod-1)/k); 
            if(opt==-1) x=qpow(x,mod-2); 
            for(int i=0;i<len;i+=k)
            {
                int w=1; 
                for(int j=i;j<i+t;++j)
                {
                    int tmp=1ll*a[j+t]*w%mod; 
                    a[j+t]=(a[j]-tmp+mod)%mod; 
                    a[j]=(a[j]+tmp)%mod; 
                    w=1ll*w*x%mod; 
                }
            }
        }
        if(opt==-1) for(int i=0,t=qpow(len,mod-2);i<len;++i) a[i]=1ll*a[i]*t%mod; 
    }
    void solve(int *a,int *b,int len)
    {      
        if(len==1) { b[0]=qpow(a[0],mod-2); return ; }
        solve(a,b,len>>1);       
        for(int i=0;i<len;++i) f[i]=a[i],g[i]=b[i]; 
        NTT(f,len<<1,1),NTT(g,len<<1,1); 
        for(int i=0;i<(len<<1);++i) f[i]=((1ll*f[i]*g[i])%mod*g[i])%mod; 
        NTT(f,len<<1,-1); 
        for(int i=0;i<len;++i)  b[i]=((b[i]<<1)%mod-f[i]+mod)%mod; 
    }
    void Inv(int *a,int *b,int len)
    {
        int m = 1;
        while(m <= len) m <<= 1; 
        solve(a,b,m); 
    }
};
int inv[N],jc[N],jv[N]; 
int p[N],G[N],C[N],F[N],D[N]; 
int main()
{
    // setIO("input"); 
    int n,m; 
    scanf("%d",&n); 
    for(m = 1;m <= n;m <<= 1);       
    inv[0] = jc[0] = inv[1] = jc[1] = jv[0] = jv[1] = 1; 
    for(int i=2;i<=n;++i)
    {
        jc[i]=1ll*jc[i-1]*i%mod; 
        inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod; 
        jv[i]=1ll*jv[i-1]*inv[i]%mod; 
    }
    p[0]=p[1]=1; 
    for(int i=2;i<=n;++i) p[i]=qpow(2,1ll*(i-1)*i/2%(mod-1));     
    for(int i=0;i<=n;++i) G[i]=1ll*p[i]*jv[i]%mod; 
    for(int i=1;i<=n;++i) C[i]=1ll*p[i]*jv[i-1]%mod; 
    NTT::solve(G,D,m); 
    NTT::NTT(D,m,1);NTT::NTT(C,m,1); 
    for(int i=0;i<m;++i) F[i]=1ll*D[i]*C[i]%mod; 
    NTT::NTT(F,m,-1); 
    printf("%lld\n",1ll*F[n]*jc[n-1]%mod); 
    return 0; 
}

  

posted @ 2019-05-28 10:22 EM-LGH 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值