COGS2353 【HZOI2015】有标号的DAG计数 I

本文详细解析了针对给定正整数n,如何计算由n个有标号点构成的不同有向无环图(DAG)数量的算法。通过递推公式结合容斥原理,实现了高效计算,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面

题目描述

给定一正整数n,对n个点有标号的有向无环图(可以不连通)进行计数,输出答案mod 10007的结果

输入格式

一个正整数n

输出格式

一个数,表示答案

样例输入

3

样例输出

25

提示

对于20%的数据:n<=5

对于50%的数据:n<=500

对于100%的数据:1<=n<=5000

题目分析

\(f(i)\)表示有\(i\)个点构成DAG图

设其中\(j\)个点出度为\(0\),则有:
\[ f(i)=\sum_{j=1}^i\binom ij2^{(i-j)\cdot j}\cdot f(i-j) \]

意思是,在\(i\)个点中选出\(j\)个点有\(\binom ij\)种方案,

\(i-j\)个点与这\(j\)个点之间随意连边,\(i-j\)个点构成的图仍为DAG的情况数。

但由于无法保证那\(i-j\)个点一定出度不为\(0\),所以需要容斥。
\[ f(i)=\sum_{j=1}^i\binom ij2^{(i-j)\cdot j}\cdot f(i-j)\cdot (-1)^{j-1} \]

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#define MAXN 0x7fffffff
typedef long long LL;
const int N=5005,mod=10007;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
int f[N],c[N][N];
int ksm(int x,int k){
    int ret=1;
    while(k){
        if(k&1)ret=ret*x%mod;
        x=x*x%mod,k>>=1;
    }
    return ret;
}
int main(){
    freopen("DAG.in","r",stdin);
    freopen("DAG.out","w",stdout);
    int n=Getint();
    c[0][0]=f[0]=1;
    for(register int i=1;i<=n;c[i++][0]=1){
        for(register int j=1;j<=i;++j){
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
            f[i]=(f[i]+c[i][j]*ksm(2,j*(i-j)%(mod-1))%mod*f[i-j]%mod*((j&1)?1:-1)+mod)%mod;
        }
    } 
    cout<<f[n]; 
    return 0;
}

转载于:https://www.cnblogs.com/Emiya-wjk/p/10055701.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值