2 条题解

  • 0
    @ 2025-10-8 16:57:37
    #include <bits/stdc++.h>
    #pragma GCC optimize(2,3,"Ofast")
    using namespace std;
    typedef long long ll;
    const int N=55;
    const int P=1e9+7;
    int n,m;
    template<typename T>T qpow(T a,ll b){
        T res=1;
        for(;b;b>>=1,a*=a)
            if(b&1)res*=a;
        return res;
    }
    class mint{
        public:
        ll val;
        mint(ll _val=0){val=(_val%P+P)%P;}
        mint operator + (const mint& _){return (val+_.val)%P;}
        mint operator +=(const mint& _){return *this=*this+_;}
        mint operator - (const mint& _){return (val-_.val+P)%P;}
        mint operator -=(const mint& _){return *this=*this-_;}
        mint operator * (const mint& _){return val*_.val%P;}
        mint operator *=(const mint& _){return *this=*this*_;}
        mint operator / (const mint& _){return *this*qpow(_,P-2);}
        mint operator /=(const mint& _){return *this=*this/_;}
        mint operator ^ (const ll  & _){return qpow(*this,_);}
        mint operator ^=(const ll  & _){return *this=*this^_;}
    };
    mint F[N][N],G[N][N][N],H[N];
    mint pow2[N*N],C[N][N];
    void init(int N){
        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];
        }
        pow2[0]=1;
        for(int i=1;i<=N*N;i++)pow2[i]=pow2[i-1]*2;
    }
    int main(){
        scanf("%d%d",&n,&m);
        init(n);
        G[0][0][0]=1;
        for(int i=1;i<=n;i++){
            H[i]=pow2[i*(i-1)/2];
            for(int j=1;j<i;j++)
                H[i]-=C[i-1][j-1]*H[j]*pow2[(i-j)*(i-j-1)/2];
            F[i][0]=H[i];
            for(int j=1;j<i;j++){
                for(int k=1;k<i;k++){
                    mint temp=C[i-1][k-1]*F[k][0];
                    mint kx=k;
                    for(int x=1;x<=min(i-k,j);x++,kx*=k)
                        F[i][j]+=temp*G[i-k][j-x][x]*kx;
                }
                F[i][0]-=F[i][j];
            }
            for(int j=0;j<i;j++)
                for(int k=1;k<=i;k++)
                    for(int p=1;p<=i;p++){
                        mint temp=C[i-1][p-1]*p;
                        for(int q=0;q<=j;q++)
                            G[i][j][k]+=temp*F[p][q]*G[i-p][j-q][k-1];
                    }
        }
        mint ans;
        for(int i=0;i<=min(m,n-1);i++)ans+=F[n][i];
        printf("%lld\n",ans.val);
    }
    

    定义

    • 以下定义中图均为有标号无向连通图
    • F[i,j] = i 个结点 j 条割边方案数
    • G[i,j,k] = i 个结点,j 条割边,k 个连通块的方案数
    • H[i] = i 个结点方案数

    状态转移方程

    • F[i,j] = \sum_{k=1}^{i-1} C(i-1,k-1) \cdot F[k,0] \cdot \sum_{x=1}^{\min(i-k,j)} G[i-k,j-x,x] \cdot k^x
    • F[i,0] = H[i] - \sum_{j=1}^{i-1} F[i,j]
    • G[i,j,k] = \sum_{p=1}^{i} \sum_{q=0}^{k} F[p,q] \cdot C(i-1,p-1) \cdot p \cdot G[i-p,j-q,k-1]
    • H[i] = 2^{i(i-1)/2} - \sum_{j=1}^{i-1} C(i-1,j-1) \cdot H[j] \cdot 2^{(i-j)(i-j-1)/2}
    • 0
      @ 2025-10-8 16:57:26
      #include<bits/stdc++.h>
      #pragma GCC optimize(2,3,"Ofast")
      using namespace std;
      typedef long long ll;
      const int N=55;
      const int P=1e9+7;
      int n,m;
      template<typename T>T qpow(T a,ll b){
          T res=1;
          for(;b;b>>=1,a*=a)
              if(b&1)res*=a;
          return res;
      }
      class mint{
          public:
          ll val;
          mint(ll _val=0){val=(_val%P+P)%P;}
          mint operator + (const mint& _){return (val+_.val)%P;}
          mint operator +=(const mint& _){return *this=*this+_;}
          mint operator - (const mint& _){return (val-_.val+P)%P;}
          mint operator -=(const mint& _){return *this=*this-_;}
          mint operator * (const mint& _){return val*_.val%P;}
          mint operator *=(const mint& _){return *this=*this*_;}
          mint operator / (const mint& _){return *this*qpow(_,P-2);}
          mint operator /=(const mint& _){return *this=*this/_;}
          mint operator ^ (const ll  & _){return qpow(*this,_);}
          mint operator ^=(const ll  & _){return *this=*this^_;}
      };
      mint F[N][N],G[N][N][N],H[N];
      mint pow2[N*N],C[N][N];
      void init(int N){
          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];
          }
          pow2[0]=1;
          for(int i=1;i<=N*N;i++)pow2[i]=pow2[i-1]*2;
      }
      int main(){
          scanf("%d%d",&n,&m);
          init(n);
          G[0][0][0]=1;
          for(int i=1;i<=n;i++){
              H[i]=pow2[i*(i-1)/2];
              for(int j=1;j<i;j++)
                  H[i]-=C[i-1][j-1]*H[j]*pow2[(i-j)*(i-j-1)/2];
              F[i][0]=H[i];
              for(int j=1;j<i;j++){
                  for(int k=1;k<i;k++){
                      mint temp=C[i-1][k-1]*F[k][0];
                      mint kx=k;
                      for(int x=1;x<=min(i-k,j);x++,kx*=k)
                          F[i][j]+=temp*G[i-k][j-x][x]*kx;
                  }
                  F[i][0]-=F[i][j];
              }
              for(int j=0;j<i;j++)
                  for(int k=1;k<=i;k++)
                      for(int p=1;p<=i;p++){
                          mint temp=C[i-1][p-1]*p;
                          for(int q=0;q<=j;q++)
                              G[i][j][k]+=temp*F[p][q]*G[i-p][j-q][k-1];
                      }
          }
          mint ans;
          for(int i=0;i<=min(m,n-1);i++)ans+=F[n][i];
          printf("%lld\n",ans.val);
      }
      /*
      =======================
      > 定义 
      - 以下定义中图均为有标号无向连通图 
      - F[i,j]= i 个结点 j 条割边方案数 
      - G[i,j,k]= i 个结点,j 条割边,k 个连通块的方案数 
      - H[i]= i 个结点方案数 
      =======================
      > 状态转移方程 
      - F[i,j] = sum{k,1,i-1} C(i-1,k-1) * F[k,0] * sum{x,1,min(i-k,j)} G[i-k,j-x,x] * k^x 
      - F[i,0] = H[i] - sum{j,1,i-1} F[i,j] 
      - G[i,j,k] = sum{p,1,i} sum{q,0,k} F[p,q] * C(i-1,p-1) * p * G[i-p,j-q,k-1] 
      - H[i]= 2^(i(i-1)/2) - sum{j,1,i-1} C(i-1,j-1) * H[j] * 2^((i-j)(i-j-1)/2) 
      =======================
      */
      • 1

      0x50 动态规划(0x5C 计数类DP)例题4:它们中的多少个

      信息

      ID
      1505
      时间
      800ms
      内存
      64MiB
      难度
      8
      标签
      递交数
      13
      已通过
      7
      上传者