【题解】有标号的DAG计数4

[HZOI 2015] 有标号的DAG计数 IV

我们已经知道了\(f_i\)表示不一定需要联通的\(i\)节点的dag方案,考虑合并

参考【题解】P4841 城市规划(指数型母函数+多项式Ln),然后答案\(h_i\)母函数\(H(x)\)就这样解

由于
\[ H(x)=\sum_{i=0}^{\inf} \dfrac {(F(x))^i} {i!} \]

\[ H(x)=e^{F(x)} \]
\(\ln\)就好了

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
 
 
using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
 
 
namespace poly{
      const int maxn=1<<19|1;
      int a[maxn],b[maxn],A[maxn],B[maxn],r[maxn];
      int savlen;
      inline void getr(const int&len){
        if(len==savlen)return;
        int cnt=0;
        for(register int t=1;t<len;t<<=1)++cnt;
        for(register int t=1;t<len;++t)
          r[t]=r[t>>1]>>1|(t&1)<<cnt>>1;
      }
      const int mod=998244353;
      const int g=3;
      inline int ksm(ll base,ll p){
        register int ret=1;
        for(base%=mod;p;p>>=1,base=1ll*base*base%mod)
          if(p&1) ret=1ll*ret*base%mod;
        return ret;
      }
      const int gi=ksm(3,mod-2);
      
 
      inline void NTT(int*a,const int&len,const int&tag){
        getr(len);
        for(register int t=1;t<len;++t)
          if(r[t]>t) swap(a[t],a[r[t]]);
        int *a1,*a0,s=g;
        if(tag!=1) s=gi;
        for(register int t=1,wn;t<len;t<<=1){
          wn=ksm(s,(mod-1)/(t<<1));
          for(register int i=0;i<len;i+=t<<1){
            a1=(a0=a+i)+t;
            for(register int j=0,w=1,tm;j<t;++j,++a1,++a0,w=1ll*w*wn%mod){
                  tm=1ll**a1*w%mod;
                  *a1=(*a0-tm)%mod;
                  *a0=(*a0+tm)%mod;
                  if(*a1<0)*a1+=mod;
            }
          }
        }
        if(tag!=1)
          for(register int t=0,in=ksm(len,mod-2);t<len;++t)
            a[t]=1ll*a[t]*in%mod;
      }
      
      void INV(int*a,int*b,const int&len){
        if(len==1){b[0]=ksm(a[0],mod-2);return;}
        INV(a,b,len>>1);
        for(register int t=0;t<len;++t) A[t]=a[t],B[t]=b[t];
        NTT(A,len<<1,1);NTT(B,len<<1,1);
        for(register int t=0,w=len<<1;t<w;++t) A[t]=1ll*A[t]*B[t]%mod*B[t]%mod;
        NTT(A,len<<1,-1);
        for(register int t=0;t<len;++t) b[t]=((b[t]+b[t])%mod-A[t]+mod)%mod;
        memset(A,0,sizeof A);
        memset(B,0,sizeof B);
      }
      
      inline void inter(int*a,int*b,const int&len){
        for(register int t=len;t;--t)
          b[t]=1ll*a[t-1]*ksm(t,mod-2)%mod;
        b[0]=0;
      }
      
      inline void dev(int*a,int*b,const int&len){
        for(register int t=0;t<len-1;++t)
          b[t]=1ll*a[t+1]*(t+1)%mod;
        b[len-1]=0;
      }
 
      
      inline void LN(int*a,int*b,const int&len){
        static int C[maxn];
        memset(C,0,sizeof C);
        INV(a,b,len);
        dev(a,C,len);
        NTT(C,len<<1,1);
        NTT(b,len<<1,1);
        for(register int t=0;t<len<<1;++t) b[t]=1ll*b[t]*C[t]%mod;
        NTT(b,len<<1,-1);
        inter(b,C,len);
        for(register int t=0;t<len;++t) b[t]=C[t];
        
      }
      
}
 
 
 
 
int g[1<<19|1],f[1<<19|1];
int jc[100005];
int inv[100005];
int n;
const int mod=998244353;
int main(){
      freopen("dagIV.in","r",stdin);
      freopen("dagIV.out","w",stdout);
      n=qr();
      jc[0]=1;
      inv[0]=1;
      for(register int t=1;t<=n;++t)
        jc[t]=1ll*jc[t-1]*t%mod;
      using poly::ksm;
      inv[n]=ksm(jc[n],mod-2);
      for(register int t=n-1;t;--t) inv[t]=1ll*(t+1)*inv[t+1]%mod;
      for(register int t=1;t<=n;++t){
        g[t]=1ll*ksm(ksm(2,1ll*t*(t-1)/2),mod-2)*inv[t]%mod;
        if(t&1) g[t]=mod-g[t];
      }       
      g[0]=1;
      int k=1;
      while(k<=n+2)k<<=1;
      poly::INV(g,f,k);
      memset(g,0,sizeof g);
      for(register int t=1;t<=n;++t)
        g[t]=1ll*ksm(2,1ll*t*(t-1)/2)%mod*f[t]%mod;
      g[0]=1;
      memset(f,0,sizeof f);
      //cout<<endl;
      poly::LN(g,f,k);
      //for(register int t=0;t<k;++t) cout<<f[t]<<' ';
      printf("%lld\n",1ll*jc[n]*f[n]%mod);
      return 0;
}

转载于:https://www.cnblogs.com/winlere/p/11258205.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值