zoukankan      html  css  js  c++  java
  • 【LGP5162】WD与积木

    题目

    场面过度玄学,容易引起不适

    我们发现我们要求的这个期望由分母和分子两部分构成

    易发现

    [Ans=frac{sum_{i=1}^nS_2(n,i) imes i imes i!}{sum_{i=1}^nS_2(n,i) imes i!} ]

    结合(NTT)求斯特林数卷积我们就能过掉(subtask2)

    考虑正解,我们显然不能再用斯特林数搞了

    于是考虑一下(dp)

    (f_n)表示分母,即(f_n=sum_{i=1}^nS_2(n,i) imes i!)

    我们发现

    [f_i=sum_{j=1}^{i}f_{i-j}inom{i}{j} ]

    我们强行规定(f_0=1)

    这个柿子我们可以这样理解,先从(i)个数里选取(j)个数作为第一组,之后剩下的(i-j)在后面自由形成若干组

    这非常正确,因为对于任何一种情况,其每一分组都有机会被选中成为第一组,而剩下的组会任意排列,于是正确性显然

    我们考虑拆开组合数

    [f_i=sum_{j=1}^if_{i-j}frac{i!}{j!(i-j)!} ]

    [frac{f_i}{i!}=sum_{j=1}^ifrac{f_{i-j}}{(i-j)!} imes frac{1}{j!} ]

    (f'_i=frac{f_i}{i!},g_i=frac{1}{i!})

    写成生成函数,别忘了我们强行规定(f_0=1)

    [F'=sum_{i=0}(sum_{j=1}^if'_{i-j}g_j+[i=0])x^i ]

    [F'=1+F'G ]

    于是(F'=(1-G)^{-1})

    但是发现好像不太得劲,因为 (1-G)的最低项为(0),我们没法求逆

    但是我们注意到(g_0)全程都没有出现,于是我们又强行规定(g_0=0)

    于是我们现在可以愉快的求逆了

    同理我们也可以表示出分母上的柿子

    [h_i=sum_{j=1}^iinom{i}{j}h_{i-j}+inom{i}{j}f_{i-j}=f_i+sum_{j=1}^iinom{i}{j}h_{i-j} ]

    这里不需要强行(h_0=1)

    我们还是按照刚才的套路得到

    [H'=frac{1}{(1-G)^2} ]

    但是并不知道为什么这里答案算出来总会多(1)

    肯定是我太菜了生成函数求错了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=262144+1005;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,ask[100005],len,rev[maxn],T;
    const LL mod=998244353;
    const LL G[2]={3,332748118};
    LL fac[maxn],ifac[maxn];
    LL D[maxn],C[maxn],K[maxn],a[maxn],b[maxn],c[maxn],t[maxn];
    inline LL ksm(LL a,LL b) {LL S=1;while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;}
    inline void NTT(LL *f,int o) {
        for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
        for(re int i=2;i<=len;i<<=1) {
            int ln=i>>1;LL og1=ksm(G[o],(mod-1)/i);
            for(re int l=0;l<len;l+=i) {
                LL t,og=1;
                for(re int x=l;x<l+ln;x++) {
                    t=(og*f[ln+x])%mod;
                    f[ln+x]=(f[x]-t+mod)%mod;
                    f[x]=(f[x]+t)%mod;
                    og=(og*og1)%mod;
                }
            }
        }
        if(!o) return;
        LL inv=ksm(len,mod-2);
        for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod;
    }
    inline void mul(int n,LL *A,LL *B) {
    	len=1;while(len<n+n) len<<=1;
    	for(re int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
    	NTT(A,0),NTT(B,0);for(re int i=0;i<len;i++) A[i]=(A[i]*B[i])%mod;
    	NTT(A,1);for(re int i=n;i<len;i++) A[i]=0;
    }
    inline void Inv(int n,LL *A,LL *B) {
        if(n==1) {B[0]=ksm(A[0],mod-2);return;}
        Inv((n+1)>>1,A,B);
        memset(C,0,sizeof(C));memset(K,0,sizeof(K)),memset(D,0,sizeof(D));
        for(re int i=0;i<n;i++) C[i]=A[i],D[i]=K[i]=B[i];
        mul(n,K,C);mul(n,K,D);
        for(re int i=0;i<n;i++) B[i]=(2ll*B[i]-K[i]+mod)%mod;
    }
    int main() {
    	T=read();
    	for(re int i=1;i<=T;i++) 
    		ask[i]=read(),n=max(n,ask[i]+1);
    	fac[0]=1;
    		for(re LL i=1;i<n;i++) fac[i]=(fac[i-1]*i)%mod;
    	ifac[n-1]=ksm(fac[n-1],mod-2);
    	for(re LL i=n-2;i>=0;--i) ifac[i]=(ifac[i+1]*(i+1))%mod;
    	for(re int i=0;i<n;i++) 
    		b[i]=mod-ifac[i],b[i]%=mod;
    	b[0]=1;b[0]%=mod;
    	Inv(n,b,a);
    	for(re int i=0;i<n;i++) t[i]=c[i]=a[i];
    	mul(n,t,c);
    	for(re int i=1;i<=T;i++) {
    		LL q=t[ask[i]],p=a[ask[i]];
    		printf("%lld
    ",q*ksm(p,mod-2)%mod-1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    NPM使用技巧
    重构老项目所悟
    Angular2开发笔记
    nodejs项目mysql使用sequelize支持存储emoji
    [原创]django+ldap+memcache实现单点登录+统一认证
    [原创]django+ldap实现单点登录(装饰器和缓存)
    [原创]django+ldap实现统一认证部分二(python-ldap实践)
    [原创]django+ldap实现统一认证部分一(django-auth-ldap实践)
    ldap部署相关,ldap双机LAM配置管理ldap备份还原
    通过pycharm使用git[图文详解]
  • 原文地址:https://www.cnblogs.com/asuldb/p/10560802.html
Copyright © 2011-2022 走看看