把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ2863】愤怒的元首(数数题)

点此看题面

大致题意:\(n\)个点的有标号\(DAG\)数目。

前言

不会数数的我实在太菜太菜。。。

\(DP\)

考虑\(DAG\)中必然存在入度为\(0\)的点,且去掉这些入度为\(0\)的点之后得到的依然是\(DAG\)

于是,我们可以设\(f_i\)表示\(i\)个点的有标号\(DAG\)数目,枚举一个\(j\)表示至少存在\(j\)个入度为\(0\)的点。

显然有此时的方案数为:

\[C_i^j\times 2^{j\times (i-j)}\times f_{i-j} \]

即,枚举选出哪\(j\)个点,枚举入度为\(0\)的点和其他点之间的边是否选择,而其他点依然形成\(DAG\)可以直接从已有状态转移。

看到至少,我们可以考虑容斥

因此得到最终的转移方程:

\[f_i=\sum_{j=1}^i(-1)^{j-1}\times C_i^j\times2^{j\times(i-j)}\times f_{i-j} \]

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 3000
#define X 1000000007
using namespace std;
int n,f[N+5],pw[N*N+5],C[N+5][N+5];
int main()
{
	RI i,j,op;for(scanf("%d",&n),pw[0]=i=1;i<=n*n;++i) (pw[i]=pw[i-1]<<1)>=X&&(pw[i]-=X);//预处理2的幂
	for(C[0][0]=i=1;i<=n;++i) for(C[i][0]=j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%X;//预处理组合数
	for(f[0]=i=1;i<=n;++i) for(op=j=1;j<=i;op=X-op,++j)//枚举j
		f[i]=(1LL*op*C[i][j]%X*pw[j*(i-j)]%X*f[i-j]+f[i])%X;//容斥转移
	return printf("%d",f[n]),0;
}
posted @ 2020-06-01 20:50  TheLostWeak  阅读(188)  评论(0编辑  收藏  举报