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

  • 相关阅读:
    POJ 1015 Jury Compromise【DP】
    POJ 1661 Help Jimmy【DP】
    HDU 1074 Doing Homework【状态压缩DP】
    HDU 1024 Max Sum Plus Plus【DP,最大m子段和】
    占坑补题。。最近占的坑有点多。。。
    Codeforces 659F Polycarp and Hay【BFS】
    Codeforces 659E New Reform【DFS】
    Codeforces 659D Bicycle Race【计算几何】
    廖大python实战项目第四天
    廖大python实战项目第三天
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12149853.html
Copyright © 2011-2022 走看看