zoukankan      html  css  js  c++  java
  • 20200104模拟赛 问题A 图样

    题目

    分析:

    老规矩,遇到期望要准备好随时投降。。。

    大致想到了按位处理,然后分别下去搜索,再用组合数加加减减一下。。。

    但是两个连通块之间连边的期望怎么算呢?

    很好,投降。。。

    下来看题解。。。

    果然是记搜。。

    首先我们设F(n,m)表示n个点取 [ 0 , 2^m )的值时所有最小生成树代价之和

    那么Ans=F(n,m) / 2^(n*m)

    再设G(S,T,m)表示一部分点集大小为S,另一部分大小为T,点权取值在[ 0 , 2^m )之间后,所有情况最小边权值的总和

    于是F(n,m)可以记搜:

    F(n,m)=

    sigma(i=1...n) C(n,i)(选哪些点) * (

    F( i , m-1 ) * 2^( (n-i) * (m-1) )(一部分向下搜索再乘方案数) +

    F( n-i , m-1 ) * 2^( i * (m-1) )(另一部分) +

    G( i , n-i , m-1)(中间连边) +

    2 ^ (m-1) * 2 ^ ( n * (m-1) )(必须花费的代价乘上方案数) )

    然后我们来求G:

    我们叒设一个函数P(S,T,m,K)表示点集S,T,取值[ 0 , 2^m )时,边权最小值大于等于K的情况数

    G(S,T,m)可以巧妙地化为sigma(i=1...(2^m-1))P(S,T,m,i)

    奥妙重重,可以脑补一下,跟前缀和差不多的感觉

    然后P就很好求了,暴力地将S和T继续按01位分割下去,某一位全部都不分割时统计入答案

    三重记搜,式子还这么难

    神仙题Orz

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    
    #define maxn 55
    #define maxm 9
    #define MOD 258280327
    
    using namespace std;
    
    inline long long getint()
    {
        long long num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int n,m;
    long long C[maxn][maxn],F[maxn][maxm],G[maxn][maxn][maxm],P[maxn][maxn][maxm][1<<maxm],pw[maxn*maxm];
    
    inline long long ksm(long long num,long long k)
    {
        long long ret=1;
        for(;k;k>>=1,num=num*num%MOD)if(k&1)ret=ret*num%MOD;
        return ret;
    }
    
    inline long long getP(int S,int T,int M,int K)
    {
        if(S>T)swap(S,T);
        if(!S||K<=0)return pw[(S+T)*M];
        if(K>=(1<<M))return 0;
        if(~P[S][T][M][K])return P[S][T][M][K];
        long long tmp=0;
        for(int i=0;i<=S;i++)for(int j=0;j<=T;j++)
            if((i==0&&j==T)||(i==S&&j==0))tmp=(tmp+getP(S,T,M-1,K-(1<<(M-1))))%MOD;
            else tmp=(tmp+getP(i,j,M-1,K)*getP(S-i,T-j,M-1,K)%MOD*C[S][i]%MOD*C[T][j]%MOD)%MOD;
        return P[S][T][M][K]=tmp;
    }
    
    inline long long getG(int S,int T,int M)
    {
        if(!M)return 0;
        if(S>T)swap(S,T);
        if(~G[S][T][M])return G[S][T][M];
        long long tmp=0;
        for(int i=1;i<(1<<M);i++)
            tmp=(tmp+getP(S,T,M,i))%MOD;
        return G[S][T][M]=tmp;
    }
    
    inline long long getF(int N,int M)
    {
        if(!M||N<2)return 0;
        if(~F[N][M])return F[N][M];
        long long tmp=2*getF(N,M-1)%MOD;
        for(int i=1;i<N;i++)
            tmp=(tmp+C[N][i]*(getF(i,M-1)*pw[(N-i)*(M-1)]%MOD+getF(N-i,M-1)*pw[i*(M-1)]%MOD+getG(i,N-i,M-1)+(1<<(M-1))*pw[N*(M-1)]%MOD))%MOD;
        return F[N][M]=tmp;
    }
    
    int main()
    {
        n=getint(),m=getint();
        pw[0]=1;for(int i=1;i<=n*m;i++)pw[i]=pw[i-1]*2%MOD;
        for(int i=0;i<=n;i++)
        {
            C[i][0]=C[i][i]=1;
            for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
        }
        memset(F,-1,sizeof F),memset(G,-1,sizeof G),memset(P,-1,sizeof P);
        printf("%lld
    ",getF(n,m)*ksm(pw[n*m],MOD-2)%MOD);
    }
    View Code

  • 相关阅读:
    sleep(),wait(),yield(),notify()
    (三)终结任务
    (二)共享受限资源
    (一)基本的线程机制
    (十八)多线程
    (十七)泛型程序设计
    视频监控中带宽及存储容量的计算
    turtle实例
    python ——钟表
    Python Tkinter Grid布局管理器详解
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12149853.html
Copyright © 2011-2022 走看看