[BZOJ2863]愤怒的元首

Description:

Pty生活在一个奇葩的国家,这个国家有n个城市,编号为1~n。

​ 每个城市到达其他城市的路径都是有向的。

​ 不存在两个城市可以互相到达。

这个国家的元首现在很愤怒,他大喊一声“气死偶咧!”,然后决定把所有的路径都毁掉再重建。

元首想知道有多少种重建的方案使得这个国家仍然奇葩。

Hint:

\(n \le 3000\)

Solution:

这题已经是弱化版了...原题1e5数据范围听说要分治FFT?不会不会

回到题目

直接求貌似不好求

考虑设 \(g[i]=(^{\ i}_{\ j})*f[i-j]*2^{i*(i-j)}\) 表示\(i\)个点的图至少\(j\)个入度为0的点的方案数

我们用\(g[i]\)来容斥,有\(n\)个点的\(DAG\)方案数\(f[n]\):

\(f[n]=\sum_{i=1}^n (-1)^{i-1} *( ^{\ n}_{\ i})*f[n-i]*2^{j*(i-j)}\)

为什么呢,因为每个入度为0个数大于\(i\)的方案都会在\(g[i]\)中被算重\(C_{n}^i\)

所以容斥后就是对的

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=3e4+5,mod=1e9+7;
int n;
int a[mxn],fac[mxn],inv[mxn],f[mxn];
inline int read() {
	char c=getchar(); int x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline int chkmax(int &x,int y) {if(x<y) x=y;}
inline int chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
	int to,nxt;
}t[mxn<<1];

int qpow(int a,int b)
{
	int res=1,base=a;
	while(b) {
		if(b&1) res=1ll*base*res%mod;
		base=1ll*base*base%mod;
		b>>=1;
	}
	return res;
}

int main()
{
	n=read(); fac[0]=inv[0]=inv[1]=f[0]=f[1]=1;
	for(int i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod;
	for(int i=2;i<=n;++i) 
		for(int j=1,opt=-1;j<=i;++j) {
			opt*=-1;
			f[i]=(f[i]+1ll*opt*f[i-j]*qpow(2,j*(i-j))%mod*qpow(fac[i-j],mod-2)%mod*qpow(fac[j],mod-2)%mod*fac[i]%mod)%mod;
		}
	printf("%d",(f[n]+mod)%mod);	
    return 0;
}

posted @ 2019-03-11 11:34  cloud_9  阅读(225)  评论(0编辑  收藏  举报