zoukankan      html  css  js  c++  java
  • AGC021F Trinity

    Link
    (f_{i,j})(i)(j)列,强制每行都有黑格子的方案数,那么答案就是(sumlimits_{i=1}^n{nchoose i}f_{i,m})
    考虑(f_{i,j})新增一列转移到(f_{i+k,j+1})有哪些情况:
    (k=0),那么相当于在第(j)列选(0sim2)个端点,贡献系数为(1+i+{ichoose2})
    (k>0),那么我们考虑求(b_{j+1}-1,c_{j+1}+1)不同的方案。注意这两个格子都是白色的,因此不会在多出来的(k)行,贡献系数为({i+k+2choose k+2})。具体来说是在(i+k+2)行(因为是(b_j-1,c_j+1))中选(k+2)行,把最上/下面一行作为(b_{j+1}-1,c_{j+1}+1),中间的(k)行作为新的(k)行。
    注意到第二部分的转移是一个卷积的形式,NTT优化即可。

    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int N=1<<14|1,P=998244353;
    int n,m,lim,fac[N],ifac[N],w[N],rev[N],f[N],g[N],t[N];
    int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
    void dec(int&a,int b){a-=b,a+=a>>31&P;}
    void mul(int&a,int b){a=1ll*a*b%P;}
    int pow(int a,int b){int r=1;for(;b;b>>=1,mul(a,a))if(b&1)mul(r,a);return r;}
    void init(int n)
    {
        int half=(lim=1<<(33-__builtin_clz(n)))/2,g=pow(3,(P-1)/lim);
        w[half]=fac[0]=ifac[0]=1;
        for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? half:0),mul(fac[i]=fac[i-1],i),ifac[i]=pow(fac[i],P-2);
        for(int i=half+1;i<lim;++i) mul(w[i]=w[i-1],g);
        for(int i=half-1;i;--i) w[i]=w[i<<1];
    }
    void NTT(int*a,int f)
    {
        if(!~f) std::reverse(a+1,a+lim);
        for(int i=1;i<lim;++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
        for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=1ll*a[i+j+k]*w[i+k]%P,dec(a[i+j+k]=a[j+k],x),inc(a[j+k],x);
        if(!~f) for(int i=0,x=P-(P-1)/lim;i<lim;++i) mul(a[i],x);
    }
    int main()
    {
        int n=read(),m=read(),ans=0;
        init(n),memcpy(g+1,ifac+3,4*n),NTT(g,1),f[0]=t[0]=1;
        for(int i=1;i<=m;++i)
        {
    	NTT(f,1);
    	for(int j=0;j<lim;++j) mul(f[j],g[j]);
    	NTT(f,-1);
            for(int j=0;j<=n;++j) t[j]=(1ll*f[j]*fac[j+2]+t[j]*(j*(j+1)/2+1ll))%P,mul(f[j]=t[j],ifac[j]);
    	memset(f+n+1,0,4*(lim-n-1));
        }
        for(int i=0;i<=n;++i) inc(ans,1ll*ifac[i]*ifac[n-i]%P*t[i]%P);
        mul(ans,fac[n]),printf("%d",ans);
    }
    
  • 相关阅读:
    组合模式
    数据去重
    combiner
    合并文档
    对象锁 区别 类锁
    一个简单的死锁示例
    线程安全的单例模式
    线程安全与不安全(误解)
    tf.nn.max_pool 池化
    tf.nn.depthwise_conv2d 卷积
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12884627.html
Copyright © 2011-2022 走看看