• CTS2019


    随机立方体

    Luogu
    LOJ
    UOJ
    首先很显然的是最多存在(lim=min(n,m,l))个极大数字,记(V=nml)
    (f_i)表示有至少(i)个极大数字的概率,(g_i)表示恰好有(i)个极大数字的概率,那么根据二项式反演我们有

    [f_i=sumlimits_{j=i}^{lim}{jchoose i}g_j,g_i=sumlimits_{j=i}^{lim}(-1)^{j-i}{jchoose i}f_j ]

    选出(i)个极大值点的方案数(有顺序)为(n^{underline i}m^{underline i}l^{underline i})
    此时有(a_i=V-(n-i)(m-i)(l-i))个被限制的点。
    剩下的(V-a_i)个数没有任何限制,我们从(V)个数中任选(V-a_i)个分配给它们,同时这(V-a_i)个数可以自由排列,方案数为(frac{V!}{a_i!})
    剩下的就是填充(a_i)个位置的数,方案数为(prodlimits_{j=0}^{i-1}frac{(a_{j+1}-1)!}{a_j!})
    因此总方案数为(n^{underline i}m^{underline i}l^{underline i}V!prodlimits_{j=1}^ifrac1{a_i})
    因为(f_i)是概率,所以还要除掉总方案数(V!),即(f_i=n^{underline i}m^{underline i}l^{underline i}prodlimits_{j=1}^ifrac1{a_i})
    (prodlimits_{j=1}^ifrac1{a_i})用类似于阶乘逆元的方法计算即可。

    #include<cstdio>
    #include<algorithm>
    using i64=long long;
    using i128=__int128;
    const int N=5000007,P=998244353;
    i64 fac[N],ifac[N],a[N];
    int read(){int x;scanf("%d",&x);return x;}
    i64 pow(i64 a,int b){i64 r=1;for(;b;b>>=1,a=a*a%P)if(b&1)r=r*a%P;return r;}
    int main()
    {
        fac[0]=1;for(int i=1;i<=5000000;++i) fac[i]=i*fac[i-1]%P;
        ifac[5000000]=pow(fac[5000000],P-2);for(int i=5000000;i;--i) ifac[i-1]=i*ifac[i]%P;
        for(int T=read();T;--T)
        {
    	int n=read(),m=read(),l=read(),k=read(),lim=std::min({n,m,l});i64 ans=0,inv=1;i128 V=(i128)n*m*l;
    	for(int i=1;i<=lim;++i) a[i]=(V-(i128)(n-i)*(m-i)*(l-i))%P,inv=inv*a[i]%P;
    	inv=pow(inv,P-2);i64 t=fac[n]*fac[m]%P*fac[l]%P*ifac[k]%P,z;
    	for(int i=lim;i>=k;--i) z=t*fac[i]%P*ifac[i-k]%P*ifac[n-i]%P*ifac[m-i]%P*ifac[l-i]%P*inv%P,ans+=(i-k)&1? P-z:z,inv=inv*a[i]%P;
    	printf("%lld
    ",ans%P);
        }
    }
    

    氪金手游

    Luogu
    LOJ
    UOJ
    这个限制大概是外向树套内向树的形式(外向树中的每个点都可能是一棵内向树的根),不妨令(1)为根。
    (f_{u,i})表示(u)点子树内的(sum W=i)的情况下的合法概率,那么答案就是(sum f_{1,i}),初始时(f_{u,i}=frac{ip_{u,i}}{sum p_{u,j}})(我们将(frac{W_u}{sum W_i})中的(W_u)在此处计算,(frac1{sum W_i})在最后处理)。
    (F_u(x)=sumlimits f_{u,i}x^i)
    对于边(u ightarrow v),我们有转移(F_u(x)leftarrow F_u(x)F_v(x))
    对于边(uleftarrow v),考虑容斥,我们有转移(F_u(x)leftarrow F_u(x)(1-F_v(x)))
    这样转移完之后还需要(f_{u,i}leftarrow frac{f_{u,i}}i)

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<utility>
    using i64=long long;
    using pi=std::pair<int,int>;
    const int N=3007,P=998244353;
    int size[N];i64 inv[N],t[N],f[N][N];std::vector<pi>e[N];
    int read(){int x;scanf("%d",&x);return x;}
    i64 pow(i64 a,int b){i64 r=1;for(;b;b>>=1,a=a*a%P)if(b&1)r=r*a%P;return r;}
    void inc(i64&a,i64 b){a+=b-P,a+=a>>63&P;}
    void dec(i64&a,i64 b){a-=b,a+=a>>63&P;}
    void dfs(int u,int fa)
    {
        size[u]=1;
        for(auto it:e[u])
        {
    	int v=it.first;
    	if(v==fa) continue;
    	dfs(v,u),memcpy(t+1,f[u]+1,24*size[u]),memset(f[u]+1,0,24*size[u]);
    	for(int j=1;j<=3*size[u];++j)
    	    if(t[j])
    		for(int k=1;k<=3*size[v];++k)
    		    if(f[v][k])
    		    {
    			i64 x=t[j]*f[v][k]%P;
    			if(it.second) inc(f[u][j+k],x); else dec(f[u][j+k],x),inc(f[u][j],x);
    		    }
    	size[u]+=size[v];
        }
        for(int i=1;i<=3*size[u];++i) f[u][i]=inv[i]*f[u][i]%P;
    }
    int main()
    {
        int n=read();i64 ans=0;inv[0]=inv[1]=1;
        for(int i=2;i<=3*n;++i) inv[i]=(P-P/i)*inv[P%i]%P;
        for(int i=1,a,b,c,d;i<=n;++i) a=read(),b=read(),c=read(),d=pow(a+b+c,P-2),f[i][1]=1ll*a*d%P,f[i][2]=2ll*b*d%P,f[i][3]=3ll*c*d%P;
        for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].emplace_back(v,1),e[v].emplace_back(u,0);
        dfs(1,0);
        for(int i=1;i<=3*n;++i) inc(ans,f[1][i]);
        printf("%lld",ans);
    }
    
  • 相关阅读:
    linux环境下安装redis扩展
    LINUX环境下SVN安装与配置(利用钩子同步开发环境与测试环境)
    Linux环境下网卡配置
    MAC 下虚拟主机的配置
    从json_encode过来的的字符串被返回到html页面时的解析
    for循环绑定事件,闭包思想!
    js8月-4号,,思想
    三种添加事件的方式
    smarty第一天
    5秒钟后自动跳转!!!!
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13039796.html
Copyright © 2020-2023  润新知