题意
给出一个有向无环图(节点1必然可以到达所有点)和任意一条边(可以是自环),问以1为根的生成树有多少种。有向图的生成树是指每个节点与父节点的连边必然是由父节点连向它。
n<=100000,m<=200000
分析
想到了最后一步,但是没想到这个东西可以用dp来求。。。
我们发现一个DAG的生成树数量必然是除了1以外所有点的度数乘积。证明的话随便yy一下就好了。
现在多了一条边,我们考虑用同样的方法来求。但是发现会多算一些情况。这些情况必然都是选了新加入的那条边并且这条边在一个环中。那么就要考虑容斥掉这些情况对答案的贡献。
这些情况对答案的贡献为∑S为y到x一条路径上的点集Πni=2且i∉Sdegree[i]
而这个是可以用dp来求的。
设f[i]表示∑S为y到i一条路径上的点集Πni=2且i∉Sdegree[i]
显然有f[i]=∑j−>if[j]degree[i]
初值为f[y]=Πni=2且i!=ydegree[i]
注意y=1要特判掉。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N=100005;
const int MOD=1000000007;
int n,m,s,t,inv[N*2],tmp[N],tot,last[N],cnt,d[N],f[N],a[N];
struct edge{int to,next;}e[N*2];
queue<int> que;
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
}
void toposort()
{
for (int i=1;i<=n;i++) if (!d[i]) que.push(i);
while (!que.empty())
{
int u=que.front();que.pop();
a[++tot]=u;
for (int i=last[u];i;i=e[i].next)
{
tmp[e[i].to]--;
if (!tmp[e[i].to]) que.push(e[i].to);
}
}
}
void get_inv()
{
inv[1]=1;
for (int i=2;i<=m+1;i++) inv[i]=(LL)(MOD-MOD/i)*inv[MOD%i]%MOD;
}
int main()
{
n=read();m=read();s=read();t=read();
for (int i=1;i<=m;i++)
{
int x=read(),y=read();
addedge(x,y);
d[y]++;tmp[y]++;
}
toposort();
get_inv();
d[t]++;
int ans=1;
for (int i=2;i<=n;i++) ans=(LL)ans*d[i]%MOD;
if (t==1)
{
printf("%d",ans);
return 0;
}
f[t]=(LL)ans*inv[d[t]]%MOD;
for (int i=1;i<=tot;i++)
{
int x=a[i];
if (!f[x]) continue;
for (int j=last[x];j;j=e[j].next) f[e[j].to]=(f[e[j].to]+(LL)f[x]*inv[d[e[j].to]]%MOD)%MOD;
}
printf("%d",(ans-f[s]+MOD)%MOD);
return 0;
}