• 国庆集训 Day1 T2 生成图 DP


    国庆集训 Day1 T2 生成图

    现在要生成一张(n)个点的有向图。要求满足:
    1.若有 a->b的边,则有 b->a 的边
    2.若有 a->b 的边和 b->c 的边,则有 a->c 的边
    3.至少有一个点没有自环。
    求方案数模上(m)
    (n≤2000,2≤m≤1,000,000,007)

    样例:
    input
    2 5
    output
    3

    有点难度的DP,首先需要明确的是在一个连通图中每一个点都有自环(样例可体现),所以有点没有自环当且仅当这一个点独立为一个联通块

    (g[i])表示(i)个点自由组合,且每个点都存在自环的方案数,(f[i])表示(i)个点自由组合,且至少有1个点没有自环的方案数((f[n])即答案)

    考虑(f[i])转移有以下情况:

    • (i)个点孤立且没有自环,即(f[i]+=f[i-1]+g[i-1])
    • (i)个点孤立且自环,即(f[i]+=f[i-1])
    • (i)个点与前(i-1)个点中的(j-1)个点构成一个大小为(j)的联通块,即(f[i]+=sum_{j=2}^{i-1}f[i-j] imes C_{i-1}^{j-1})

    考虑(g[i])转移有以下情况:

    • (i)个点孤立且自环,即(g[i]+=g[i-1])
    • 类似的,第(i)个点与前(i-1)个点中的(j-1)个点构成一个大小为(j)的联通块,即(g[i]+=sum_{j=2}^{i-1}g[i-j] imes C_{i-1}^{j-1})

    为求(C_n^m),我们可以利用杨辉三角,第(i)行第(j)列((i)从0开始)即为(C_i^j)

    #include <cstdio>
    #define MAXN 2002
    #define ll long long
    using namespace std;
    ll C[MAXN][MAXN]; //C[n][m]
    ll f[MAXN],g[MAXN];
    int n,MOD;
    int main(){
        scanf("%d %d", &n, &MOD);
        for(int i=0;i<=n;++i){
            C[i][0]=1;
            for(int j=1;j<=i;++j)
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
        }
        f[1]=1;
        g[1]=1;
        for(int i=2;i<=n;++i){
            g[i]=g[i-1]%MOD;
            for(int j=2;j<=i-1;++j)
                g[i]=(g[i]+g[i-j]*C[i-1][j-1]%MOD)%MOD;
            g[i]=(g[i]+1)%MOD;
            f[i]=(f[i-1]+f[i-1]+g[i-1])%MOD;
            for(int j=2;j<=i-1;++j)
                f[i]=(f[i]+f[i-j]*C[i-1][j-1]%MOD)%MOD;
        }
        printf("%lld", f[n]);
        return 0;
    }
    

    一开始题读错了导致后面DP推错了,以后注意要仔细揣摩样例与题意

  • 相关阅读:
    这些例子很炫,感兴趣的童鞋可以了解一下
    Java经典习题24
    Java经典习题23
    Java经典练习题22
    Java经典习题21
    Java经典习题20
    Java经典练习题19
    Java经典练习题18
    Java经典习题17
    Java经典习题16
  • 原文地址:https://www.cnblogs.com/santiego/p/11615869.html
Copyright © 2020-2023  润新知