zoukankan      html  css  js  c++  java
  • [2016北京集训试题8]连在一起的幻想乡[dp+无向图计数]

    Description

    Solution

    本博客参考yww大佬的博客,为了加深理解我就自己再写一遍啦。

    以下的“无向图”均无重边无自环。

    定义f0[n]为n个点构成的无向图个数,f1[n]为n个点构成的无向图的总边数,f2[n]为所有(n个点构成的无向图的边数的平方)之和。

    g0[n]为n个点构成的连通无向图个数,g1[n]为n个点构成的连通无向图的总边数,g2[n]为所有(n个点构成的连通无向图的边数的平方)之和。

    设$m[i]=i*(i-1)/2$

    每条边可以选或不选,所以$f0[i]=2^{m[i]}$

    由于每条边会在$2^{m[i]-1}$个图中被选,$f1[i]=m[i]*2^{m[i]-1}$

    求f2的公式要运用一个套路:枚举与1号点连通的边数j,则$f2[i]=sum_{j=0}^{i-1}*sum _{k=0}^{m[i]-j}*((j+k)^{2}$*(i-1个点的无向图边数为k的个数))

    即$f2[i]=sum_{j=0}^{n-1}$*[(i-1个点无向图个数*j)的平方+2*j*(i-1个点无向图总边数)+所有(i-1个点构成的无向图的边数的平方)之和)

    故$f2[i]=sum_{j=0}^{n-1}*inom{i-1}{j}*(f2[i-1]+2*j*f1[i-1]+j^{2}*f0[i-1])$。

    我们枚举点1所在连通块点数,$g0[i]=f0[i]-sum _{j=1}^{i-1}*inom{i-1}{j-1}g0[j]*f0[i-j]$
    $g1[i]=f1[i]-sum _{j=1}^{i-1}*inom{i-1}{j-1}(g0[j]*f1[i-j]+g1[j]*f0[i-j])$

    $g2[i]=f2[i]-sum _{j=1}^{i-1}*inom{i-1}{j-1}(g0[j]*f2[i-j]+2*g1[j]*f1[i-j]+g2[j]*f0[i-j])$

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    int n,mod;
    ll C[2010][2010],m[2010],g0[2010],g1[2010],g2[2010],f0[2010],f1[2010],f2[2010];
    ll ksm(ll x,ll k)
    {ll re=1;if (k==-1) return 0;while (k){if (k&1)re=re*x%mod;k>>=1;x=x*x%mod;}return re;}
    int main()
    {
        scanf("%d%d",&n,&mod);
        for (int i=0;i<=n;i++) C[i][0]=1;
        for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        for (int i=1;i<=n;i++) m[i]=i*(i-1)/2;
        for (int i=1;i<=n;i++) f0[i]=ksm(2,m[i]),f1[i]=m[i]*ksm(2,m[i]-1)%mod;
        for (int i=1;i<=n;i++) 
            for (int j=0;j<i;j++) 
            f2[i]=(f2[i]+(f2[i-1]+2*j*f1[i-1]+j*j*f0[i-1])%mod*C[i-1][j]%mod+mod)%mod;
        for (int i=1;i<=n;i++) 
        {
            g0[i]=f0[i];g1[i]=f1[i];g2[i]=f2[i];
            for (int j=1;j<i;j++)
            {
                g0[i]=(g0[i]-C[i-1][j-1]*g0[j]%mod*f0[i-j]%mod+mod)%mod;
                g1[i]=(g1[i]-C[i-1][j-1]*((g0[j]*f1[i-j]+g1[j]*f0[i-j])%mod)%mod+mod)%mod;
                g2[i]=(g2[i]-C[i-1][j-1]*((g0[j]*f2[i-j]+2*g1[j]*f1[i-j]+g2[j]*f0[i-j])%mod)%mod+mod)%mod;
            }
        }
        printf("%lld",g2[n]);
    }
  • 相关阅读:
    react路由组件&&非路由组件
    react函数式组件(非路由组件)实现路由跳转
    react使用antd组件递归实现左侧菜单导航树
    【LeetCode】65. Valid Number
    【LeetCode】66. Plus One (2 solutions)
    【LeetCode】68. Text Justification
    【LeetCode】69. Sqrt(x) (2 solutions)
    【LeetCode】72. Edit Distance
    【LeetCode】73. Set Matrix Zeroes (2 solutions)
    【LeetCode】76. Minimum Window Substring
  • 原文地址:https://www.cnblogs.com/coco-night/p/9657962.html
Copyright © 2011-2022 走看看