zoukankan      html  css  js  c++  java
  • 【题解】有标号的DAG计数2

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

    (I)中DP只有一个数组,

    [dp_i=sum{ichoose j}2^{j(i-j)}dp_{i-j}(-1)^{j+1} ]

    不会...

    傻啊直接多项式球逆,借鉴一些luogu那道模板分治FFT

    这里主要有个很烦人的(ji-j^2),现在要构造成(j,i-j,i)的的形式就好了,神tst告诉我们

    [ij = inom{i}{2} + inom{j+1}{2} - inom{i-j}{2}=dfrac {i(i-1)+j(j+1)-(i-j)(i-j-1)}{2} ]

    带进去,化简

    [frac{f_i}{i!2^inom{i}{2}} = sumlimits_{j=1}^i dfrac{(-1)^{j+1}}{j!2^inom{j}{2}} dfrac{f_{i-j}}{(i-j)!2^inom{i-j}{2}} ]

    (F(x)=sum dfrac{f_i}{i!2^inom{i}{2}} x^i)(H(x)=sum dfrac{(-1)^{j+1}}{j!2^inom{j}{2}}x^j) 上式等价于

    [F(x)=G(x)(F(x)-1) ]

    直接球逆得到 (G(x))

    //@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<<18|1;
          int r[maxn];
          int savcnt;
          inline void getr(const int&len){
    	    if(len==savcnt)return;
    	    savcnt=len;
    	    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(const int&base,const ll&p){
    	    register int ret=1;
    	    for(register ll t=p,b=base%mod;t;t>>=1,b=1ll*b*b%mod)
    		  if(t&1) ret=1ll*ret*b%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=0;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 k=0,w=1,m;k<t;++k,++a1,++a0,w=1ll*w*wn%mod){
    			      m=1ll*w**a1%mod;
    			      *a1=(*a0+mod-m)%mod;
    			      *a0=(*a0    +m)%mod;
    			      
    			}
    		  }
    	    }
    	    if(tag!=1)
    		  for(register int t=0,w=ksm(len,mod-2);t<len;++t)
    			a[t]=1ll*a[t]*w%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);
    	    static int A[maxn],B[maxn];
    	    for(register int t=0;t<len<<1;++t) A[t]=B[t]=0;
    	    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;t<len<<1;++t) B[t]=1ll*A[t]*B[t]%mod*B[t]%mod;
    	    NTT(B,len<<1,-1);
    	    for(register int t=0;t<len;++t) b[t]=((b[t]+b[t])%mod+mod-B[t])%mod;
    	    
          }
          
                
    }
     
    int g[1<<19|1],f[1<<19|1];
    int jc[100005];
    int inv[100005];
    int n;
    const int mod=998244353;
    int main(){
          freopen("dag_count.in","r",stdin);
          freopen("dag_count.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)k<<=1;
          poly::INV(g,f,k);
          printf("%lld
    ",1ll*jc[n]*ksm(2,1ll*n*(n-1)/2)%mod*f[n]%mod);
          return 0;
    }
    
  • 相关阅读:
    Linux内核同步
    Linux内核同步
    Linux内核同步
    Linux内核同步
    Linux内核同步
    Linux中断
    Linux中断
    Linux中断
    Linux中断
    Linux中断
  • 原文地址:https://www.cnblogs.com/winlere/p/11258188.html
Copyright © 2011-2022 走看看