BZOJ2863: 愤怒的元首

很明显这一题就是要求DAG组合数
问了tangjz 他直接甩给我一个公式…
不敢问证明感觉根据块的大小分一下可以搞出来?
有一个公式:
A[i]=ik=1(1)k1Cki2k(ik)A[ik]
其中 A[0]=1
A[i] 表示有i个节点时的答案 包括不连边的情况

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const
   int Mod=1000000007;
int fact[2000001],fact_[2000001];
int Max=2000000;


int S[9193991];
int ff(int x,int yt)
{
 if(x==2&&yt<=9000000)
      if(S[yt])return S[yt];
   int base=1,res=1,M=x,y=yt;
    while(y)
    {
       if(y&base)
           y^=base,res=res*1ll*M%Mod;
        base<<=1;
        M=M*1ll*M%Mod;
    }
 if(x==2&&yt<=9000000)
    return S[yt]=res;
  return res;
}
int A[4001];
char c;
inline void read(int &a)
{
  a=0;do c=getchar();while(c<'0'||c>'9');
  while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}

int main()
{
    int i,j,k;
    int n,m;
    read(n); 
    fact[1]=1;
    fact[0]=fact[1]=fact_[1]=fact_[0]=1;
    Max=n;
    for(i=2;i<=Max;i++)
    fact[i]=fact[i-1]*1ll*i%Mod;
    fact_[Max]=ff(fact[Max],Mod-2);
    for(int i=Max-1;i;i--)
     fact_[i]=fact_[i+1]*(i+1ll)%Mod;
    int ans=0;
    A[0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            A[i]+=((((j&1?1ll:-1ll)*fact[i]*fact_[i-j]%Mod)*fact_[j]%Mod)*A[i-j]%Mod)*ff(2,j*(i-j))%Mod,A[i]%=Mod;
    printf("%d\n",(A[n]+Mod)%Mod);
    return 0;
}

你可能感兴趣的:(BZOJ2863: 愤怒的元首)