可以转化为算有限制的purfer序列的方案数
满足m个条件的序列方案数可以直接算,详见BZOJ1005
然后知道n 个点的生成树的数量为 n^(n−2)
再分别求满足1,2,…,m个条件的方案数
容斥一下
这位大佬说得比较详细
#include<cstdio>
#define LL long long
#define N 1000000
#define P 1000000007
using namespace std;
int n,m,a[N+5],b[N+5],mark[N+5];
LL fac[N+5],inv[N+5];
LL ksm(LL n,LL k)
{
LL tmp=1;
while(k)
{
if(k&1) tmp=tmp*n%P;
k>>=1;n=n*n%P;
}
return tmp;
}
void init()
{
int i;
for(i=1,fac[0]=1;i<=n;++i) fac[i]=fac[i-1]*i%P;
for(i=2,inv[1]=1;i<=n;++i) inv[i]=(P-P/i)*inv[P%i]%P;
for(i=1,inv[0]=1;i<=n;++i) inv[i]=inv[i-1]*inv[i]%P;
}
int main()
{
scanf("%d %d",&n,&m);
if(n==1) {puts("1");return 0;}
init();
int i;
for(i=1;i<=m;++i) scanf("%d %d",&a[i],&b[i]),--b[i];
LL ans=0;int state,all=1<<m;
for(state=0;state<all;++state)
{
for(i=1;i<=m;++i) mark[i]=0;
int cnt=0,num=0,tag=1,tmp=fac[n-2];
for(i=1;i<=m;++i)
if((state>>(i-1))&1)
{
if(mark[a[i]]){tag=0;break;}
else mark[a[i]]=1;
++cnt;
num+=b[i];
tmp=1ll*tmp*inv[b[i]]%P;
}
if(!tag||num>n-2) continue;
tmp=1ll*tmp*inv[n-2-num]%P*ksm(n-cnt,n-2-num)%P;
if(cnt&1) ans=(ans-tmp+P)%P;
else ans=(ans+tmp)%P;
}
printf("%lld\n",ans);
}