bzoj链接
小视野链接
###题目大意
给出一个DAG,现在新加一条边(给出:
x
→
y
x\rightarrow y
x→y),求以1为根生成的外向树的个数。(题目保证图中从1节点能到达所有节点,可能有自环)
###题解
这种解法是大神zjr想出来的:。
首先算出每个点的入度
d
e
g
i
deg_i
degi
如果没有环,答案就为
∏
i
=
2
n
d
e
g
i
\prod_{i=2}^ndeg_i
∏i=2ndegi,因为每个点可以任意选择一条入边。
若加上的边仍没有环或不能选上(连上1或自环),答案也是如此。
然而懒得判有环无环,这两种情况合在一起考虑,这时答案为不加这条边的方案加上不加的方案。不加的方案数显然是
∏
i
=
2
n
d
e
g
i
\prod_{i=2}^ndeg_i
∏i=2ndegi(deg中不计新加的贡献)。
考虑加上这条边的答案。若无环:先单独把这条边取出来,把树分为以1为根的子树和以
y
y
y为根的子树,子树中随便取,必须取
x
→
y
x\rightarrow y
x→y,
y
y
y的入边不能取,答案为
∏
i
=
2
,
i
̸
=
y
n
d
e
g
i
=
∏
i
=
2
n
d
e
g
i
d
e
g
y
\prod_{i=2,i\not= y}^ndeg_i=\frac{\prod_{i=2}^ndeg_i}{deg_y}
∏i=2,i̸=yndegi=degy∏i=2ndegi。若有环,规定只选一条1至
x
x
x的路径,其他都不选,这样答案为
∣
S
∣
∗
∏
i
=
2
,
i
̸
=
y
,
i
̸
∈
S
n
d
e
g
i
=
1
d
e
g
y
∗
∏
i
=
2
n
d
e
g
i
∗
∣
S
∣
∗
∏
i
∈
S
1
d
e
g
i
|S|*\prod_{i=2,i\not=y,i\not\in S}^ndeg_i=\frac{1}{deg_y}*\prod_{i=2}^ndeg_i*|S|*\prod_{i\in S}\frac{1}{deg_i}
∣S∣∗∏i=2,i̸=y,i̸∈Sndegi=degy1∗∏i=2ndegi∗∣S∣∗∏i∈Sdegi1(S为从根节点不经过y到达x的路径点集)。后一部分可以用DP算出来
d
p
[
u
]
=
∑
u
→
v
d
p
[
v
]
d
e
g
[
v
]
dp[u]=\sum_{u\rightarrow v}\frac{dp[v]}{deg[v]}
dp[u]=∑u→vdeg[v]dp[v],边界为
d
p
[
i
]
=
(
i
=
=
X
)
dp[i]=(i==X)
dp[i]=(i==X)。(注意不能进过y)。
由于在无环的情况下,这个DP值不影响答案,所以一起计算更方便
###代码
//#pragma GCC optimize(3)
#include<iostream>
#include<iomanip>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#define ll long long
#define db double
#define inf 100009
#define infm 100009
#define INF (ll)1e15
#define mod 1000000007LL
#define pi acos(-1)
#define rd(n) {n=0;char ch;int f=0;do{ch=getchar();if(ch=='-'){f=1;}}while(ch<'0'||ch>'9');while('0'<=ch&&ch<='9'){n=(n<<1)+(n<<3)+ch-48;ch=getchar();}if(f)n=-n;}
using namespace std;
int n,m,X,Y;
ll inv[inf];
ll getinv(ll x){
int tmpx=(ll)x;
/* if (inv[tmpx]){
return inv[tmpx];
}*/
ll ans=1LL,k=mod-2LL;
while (k){
if (k&1LL){
ans=(ans*x)%mod;
}
x=(x*x)%mod;
k/=2LL;
}
// inv[tmpx]=ans;
return ans;
}
struct edge{
int y,nxt;
edge(){}
edge(int yy,int nn){
y=yy,nxt=nn;
}
}e[inf*2];
int head[inf],ecnt;
void addedge(int x,int y){
ecnt++;
e[ecnt]=edge(y,head[x]);
head[x]=ecnt;
return;
}
ll deg[inf],dp[inf];
bool vis[inf];
void dfs(int u){
vis[u]=1;
if (u==X){
dp[u]=1LL;
return;
}
else if (u==Y){
return;
}
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].y;
if (!vis[v]){
dfs(v);
}
dp[u]=(dp[u]+getinv(deg[v])*dp[v]%mod)%mod;
}
return;
}
int main(){
rd(n) rd(m) rd(X) rd(Y)
int x,y;
for (int i=1;i<=m;i++){
rd(x) rd(y)
addedge(x,y);
deg[y]++;
}
ll ans=1LL;
for (int i=2;i<=n;i++){
ans=(ans*deg[i])%mod;
}
if (X==Y || Y==1){
printf("%lld\n",ans);
return 0;
}
dfs(1);
ans=(ans+ans*dp[1]%mod*getinv(deg[Y])%mod)%mod;
printf("%lld\n",ans);
return 0;
}