zoukankan      html  css  js  c++  java
  • LOJ #6402. yww 与校门外的树 多项式求逆

    题意:略

    我们发现对于 $n$ 棵树,有用的是所有树的相对大小关系.

    而随机生成 $[0,1]$ 之间的实数的相对大小关系可以等价于随机生成一个排列的相对大小关系(我们可以认为这个小数是无限长的,一定能比较出两者大小)

    此问题就转化为:对于 $n!$ 种排列,权值综合为多少 $?$

    我们定义一些互相可以到达的树为一个连通块,然后我们发现如果一个排列中 $l$ 能连向 $r$,那么在该排列中 $[l,r]$ 一定相互联通.

    所以,对于一个排列 $P$ 来说,假设有 $x$ 个连通块,那么这 $x$ 个连通块一定是从头开始值域依次递减的.

    例如:$[8,10],[5,7],[3,4],[1,2]$

    令 $f[n]$ 表示由 $1$ ~ $n$ 这 $n$ 个元素构成的连通块大小为 $n$ 的排列数.(即 $1$ 到 $n$ 全部联通)

    那么 $Ans[n]=sum_{i=0}^{n-1}Ans[i] imes f[n-i] imes (n-i)$.

    构造生成函数 $ANS(x)=sum_{i=0}^{infty} Ans[i] imes x^i$,$M(x)=sum_{i=1}^{infty} i imes f[i] imes x^i$

    $Rightarrow ANS(x)-1=ANS(x)M(x)$

    $Rightarrow ANS(x)=frac{1}{1-M(x)}$

    正着求 $f[n]$ 很困难,不妨容斥一下:$f[n]=n!-sum_{i=1}^{n-1}f[i] imes (n-i)!$,即枚举序列开头的连通块,然后由于值域递减,所以后面那 $(n-i)!$ 种排列都不能与前面形成一个连通块.

    再做一个多项式求逆就求出 f 了,$Rightarrow F(x)=frac{FAC(x)-1}{FAC(x)}$   

    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <string>
    #define ll long long
    #define ull unsigned long long
    using namespace std;
    namespace IO
    {
        char buf[100000],*p1,*p2;
        #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
        int rd()
        {
            int x=0; char s=nc();
            while(s<'0') s=nc();
            while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
            return x;
        }  
        void print(int x) {if(x>=10) print(x/10);putchar(x%10+'0');}
        void setIO(string s)
        {
            string in=s+".in";
            string out=s+".out";
            freopen(in.c_str(),"r",stdin);
            // freopen(out.c_str(),"w",stdout);
        }
    };
    const int G=3;
    const int N=2000005;    
    const int mod=998244353;                 
    int A[N],B[N],w[2][N],mem[N*100],*ptr=mem,tmpa[N],tmpb[N],aa[N],bb[N];   
    inline int qpow(int x,int y)
    {
        int tmp=1;
        for(;y;y>>=1,x=(ll)x*x%mod)     if(y&1) tmp=(ll)tmp*x%mod;
        return tmp;
    }
    inline int INV(int a) { return qpow(a,mod-2); } 
    inline void ntt_init(int len)
    {
        int i,j,k,mid,x,y;
        w[1][0]=w[0][0]=1,x=qpow(G,(mod-1)/len),y=qpow(x,mod-2);
        for (i=1;i<len;++i) w[0][i]=(ll)w[0][i-1]*x%mod,w[1][i]=(ll)w[1][i-1]*y%mod;  
    }
    void NTT(int *a,int len,int flag)
    {
        int i,j,k,mid,x,y;        
        for(i=k=0;i<len;++i)
        {
            if(i>k)    swap(a[i],a[k]);
            for(j=len>>1;(k^=j)<j;j>>=1);
        }
        for(mid=1;mid<len;mid<<=1)     
            for(i=0;i<len;i+=mid<<1)
                for(j=0;j<mid;++j)   
                {
                    x=a[i+j], y=(ll)w[flag==-1][len/(mid<<1)*j]*a[i+j+mid]%mod;
                    a[i+j]=(x+y)%mod;
                    a[i+j+mid]=(x-y+mod)%mod;
                }
        if(flag==-1)
        {
            int rev=INV(len);
            for(i=0;i<len;++i)    a[i]=(ll)a[i]*rev%mod;
        }
    }       
    inline void getinv(int *a,int *b,int len,int la)    
    {
        if(len==1) { b[0]=INV(a[0]);   return; }
        getinv(a,b,len>>1,la);
        int l=len<<1,i;
        memset(A,0,l*sizeof(A[0]));       
        memset(B,0,l*sizeof(A[0]));
        memcpy(A,a,min(la,len)*sizeof(a[0]));                                               
        memcpy(B,b,len*sizeof(b[0]));      
        ntt_init(l);
        NTT(A,l,1),NTT(B,l,1);
        for(i=0;i<l;++i)  A[i]=((ll)2-(ll)A[i]*B[i]%mod+mod)*B[i]%mod;
        NTT(A,l,-1);                          
        memcpy(b,A,len<<2);   
    }  
    void get_dao(int *a,int *b,int len)
    {
        for(int i=1;i<len;++i) b[i-1]=(ll)i*a[i]%mod;
        b[len-1]=0;
    }              
    void get_jifen(int *a,int *b,int len)
    {
        for(int i=1;i<len;++i) b[i]=(ll)INV(i)*a[i-1]%mod;
        b[0]=0;
    }
    void get_ln(int *a,int *b,int len,int la)
    {
        int l=len<<1,i;
        memset(tmpa,0,l<<2);
        memset(tmpb,0,l<<2);
        get_dao(a,tmpa,min(len,la));
        getinv(a,tmpb,len,la);
        ntt_init(l);    
        NTT(tmpa,l,1),NTT(tmpb,l,1);
        for(i=0;i<l;++i) tmpa[i]=(ll)tmpa[i]*tmpb[i]%mod;
        NTT(tmpa,l,-1);
        get_jifen(tmpa,b,len);
    } 
    void get_exp(int *a,int *b,int len,int la)
    {
        if(len==1) { b[0]=1; return; }                     
        int l=len<<1,i;
        get_exp(a,b,len>>1,la);         
        for(i=0;i<l;++i)  aa[i]=bb[i]=0;
        for(i=0;i<(len>>1);++i) aa[i]=b[i];      
        get_ln(b,bb,len,len>>1);                                         
        for(i=0;i<len;++i) bb[i]=(ll)(mod-bb[i]+(i>=la?0:a[i]))%mod;                         
        bb[0]=(bb[0]+1)%mod;
        ntt_init(l);
        NTT(aa,l,1),NTT(bb,l,1);
        for(i=0;i<l;++i) aa[i]=(ll)aa[i]*bb[i]%mod;
        NTT(aa,l,-1);
        for(i=0;i<len;++i)  b[i]=aa[i];
    }
    struct poly
    {
        int len,*a;
        poly(){}
        poly(int l) {len=l,a=ptr,ptr+=l; }     
        inline void rev() { reverse(a,a+len); }
        inline void fix(int l) {len=l,a=ptr,ptr+=l;}
        inline void get_mod(int l) { for(int i=l;i<len;++i) a[i]=0;  len=l;  }
        inline poly dao()
        { 
            poly re(len-1);
            for(int i=1;i<len;++i)  re.a[i-1]=(ll)i*a[i]%mod;  
            return re;
        }
        inline poly jifen()
        {
            poly c;
            c.fix(len+1); 
            c.a[0]=0;
            for(int i=1;i<=len;++i) c.a[i]=(ll)a[i-1]*INV(i)%mod;         
            return c;
        }    
        inline poly Inv(int l)
        {             
            int lim=1;
            while(lim<=l) lim<<=1;
            poly b(lim);
            getinv(a,b.a,lim,len);                           
            b.get_mod(l);
            return b;                 
        }            
        inline poly ln(int l)
        {
            int lim=1;
            while(lim<=l) lim<<=1;               
            poly b(lim);
            get_ln(a,b.a,lim,len);
            return b;
        }                   
        inline poly exp(int l)
        {
            int lim=1;
            while(lim<=l) lim<<=1;
            poly b(lim);
            get_exp(a,b.a,lim,len);  
            return b;
        }
        inline poly q_pow(int k,int l)
        {        
            int lim=1;
            while(lim<=l) lim<<=1;
            poly b(lim),c(lim);
            get_ln(a,b.a,lim,len); 
            for(int i=0;i<b.len;++i) b.a[i]=(ll)b.a[i]*k%mod;  
            get_exp(b.a,c.a,lim,b.len);
            c.get_mod(l);
            return c;
        }                 
        inline poly operator*(const poly &b) const
        {
            poly c(len+b.len-1);
            if(c.len<=500)
            {  
                for(int i=0;i<len;++i)
                    if(a[i])   for(int j=0;j<b.len;++j)  c.a[i+j]=(c.a[i+j]+(ll)(a[i])*b.a[j])%mod;
                return c;
            }
            int n=1;
            while(n<(len+b.len)) n<<=1;
            memset(A,0,n<<2);
            memset(B,0,n<<2);
            memcpy(A,a,len<<2);                      
            memcpy(B,b.a,b.len<<2);           
            ntt_init(n); 
            NTT(A,n,1), NTT(B,n,1);
            for(int i=0;i<n;++i) A[i]=(ll)A[i]*B[i]%mod;
            NTT(A,n,-1);
            memcpy(c.a,A,c.len<<2);
            return c;
        }
        poly operator+(const poly &b) const
        {
            poly c(max(len,b.len));
            for(int i=0;i<c.len;++i)  c.a[i]=((i<len?a[i]:0)+(i<b.len?b.a[i]:0))%mod;
            return c;
        }
        poly operator-(const poly &b) const
        {
            poly c(len);
            for(int i=0;i<len;++i)
            {
                if(i>=b.len)   c.a[i]=a[i];
                else c.a[i]=(a[i]-b.a[i]+mod)%mod;
            }
            return c;
        }
        poly operator/(poly u)
        {
            int n=len,m=u.len,l=1;
            while(l<(n-m+1)) l<<=1;                    
            rev(),u.rev();     
            poly v=u.Inv(l);
            v.get_mod(n-m+1); 
            poly re=(*this)*v;
            rev(),u.rev();
            re.get_mod(n-m+1);  
            re.rev();
            return re;
        }
        poly operator%(poly u)
        {
            poly re=(*this)-u*(*this/u); 
            re.get_mod(u.len-1);
            return re;
        }              
    }Fac,F,tmp,Ans; 
    #define MAX 500001  
    int fac[N],inv[N],n;   
    void init() 
    { 
        int i,j; 
        fac[0]=inv[0]=1;   
        for(i=1;i<MAX;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=INV(fac[i]);  
    }   
    int main() 
    {
        // IO::setIO("input"); 
        int i,j;   
        scanf("%d",&n),init(); 
        Fac.fix(1+n),tmp.fix(1+n),Fac.a[0]=0;      
        for(i=1;i<=n;++i) tmp.a[i]=Fac.a[i]=fac[i];     
    
        tmp.a[0]=1;       
        tmp=tmp.Inv(1+n);        
    
    
        F=Fac*tmp; 
    
        F.get_mod(1+n),F.a[0]=1;   
        for(i=1;i<=n;++i) F.a[i]=(ll)(-(ll)i*F.a[i]%mod+mod)%mod;     
        Ans=F.Inv(1+n); 
        printf("%d
    ",Ans.a[n]);  
        return 0; 
    }
    

      

  • 相关阅读:
    线程简介
    JDBC连接数据库遇到的“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。
    项目开发中需要考虑的问题2
    JPA使用中遇到Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: XXX is not mapped
    ORA-01747: user.table.column, table.column 或列说明无效
    IDEA使用一套代码启动多个应用
    tomcat8.5部署管理控制台
    ubuntu16虚拟机迁移/移动/复制后无法上网
    centos7没有IP地址
    repmgr自动故障转移的参数配置
  • 原文地址:https://www.cnblogs.com/guangheli/p/12361898.html
Copyright © 2011-2022 走看看