bzoj 2863: 愤怒的元首

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ssl_lyy/article/details/79969146

Description

Pty生活在一个奇葩的国家,这个国家有n个城市,编号为1~n。
每个城市到达其他城市的路径都是有向的。
不存在两个城市可以互相到达。
这个国家的元首现在很愤怒,他大喊一声“气死偶咧!”,然后决定把所有的路径都毁掉再重建。
元首想知道有多少种重建的方案使得这个国家仍然奇葩。

Input

第一行一个整数:n

Output

输出n个城市的重建方案数mod(10^9+7)的结果
Hint:基图不连通也是合法方案

Sample Input

3

Sample Output

25

HINT

n <= 3000

Solution

我们可以设f[i]表示i个节点组成的DAG个数,
有一个显然的性质,一个DAG去掉入度为0的点后,仍然为一个DAG。
于是我们可以枚举新增的入度为0的点,
至少有j个入度为0的点的方案数为Cij2j(ij)f[ij]
因为选出j个点的方案为Cij,中间有j*(i-j)条可以连或不连,剩下的点组成DAG的方案为f[i-j],于是乘起来就好了。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

#define N 3030
#define P 1000000007
#define LL long long

LL f[N],c[N][N];
int n;

int rc(int x)
{
    if (x%2==0) return 1;
      else return -1;
}

LL ksm(LL x,int k)
{
    if (k==0) return 1;
    if (k==1) return x;
    LL t=ksm(x,k/2);
    if (k%2==1) return t*t%P*x%P;
      else return t*t%P;
}

int main()
{
    scanf("%d",&n);
    c[1][0]=c[1][1]=1;
    for (int i=2;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])%P;
    }
    f[0]=1; f[1]=1;
    for (int i=2;i<=n;i++)
      for (int j=1;j<=i;j++)
        f[i]=(f[i]+(rc(j-1)*(c[i][j]%P*ksm(2,j*(i-j))%P*f[i-j]%P))+P)%P;
    printf("%lld\n",f[n]);
    return 0;
}

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页