[HNOI2015]落忆枫音
Description
Solution
如果是一个DAG,那么答案显然是
\[\prod_{i=2}^n deg(i)
\]
其中\(deg(i)\)是点\(i\)的入度。加上条边后可能会成环,我们要去掉成环的情况数。考虑一个环,错误的计数只会发生在环上每个点选了自己环上的父亲,环外的点随意。所以对于每个环,多余的计数是
\[\prod_{i\notin Circle} deg(i)
\]
而环又是一个\(y\)到\(x\)的路径加上\((x,y)\)这条边构成的。所以设\(f[u]\)为从\(u\)出发到\(x\)的路径(假设其在环上)多余的贡献,那么有
\[f[u] = \sum_{(u,v)\in E} f[v] / deg[u]
\]
所以就是一个简单的记搜就行了。
Code
#include <cstdio>
#include <cstring>
typedef long long ll;
const int N = 100010;
const int M = 200010;
const ll mod = 1e9 + 7;
int hd[N], nxt[M], to[M], cnt;
ll deg[N], f[N], inv[N], n, m;
inline void adde(int x, int y) {
to[++cnt] = y;
nxt[cnt] = hd[x];
hd[x] = cnt;
}
int dfs(ll x) {
if (f[x] != -1) return f[x];
f[x] = 0;
for (int i = hd[x]; i; i = nxt[i]) {
f[x] = (f[x] + dfs(to[i])) % mod;
}
f[x] = f[x] * inv[deg[x]] % mod;
return f[x];
}
void calc() {
inv[1] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = (-mod / i * inv[mod % i] % mod + mod) % mod;
}
int main() {
int x, y;
scanf("%lld%lld%d%d", &n, &m, &x, &y);
for (int i = 1, x, y; i <= m; ++i) {
scanf("%d%d", &x, &y);
adde(x, y);
deg[y]++;
}
ll ans = 1, sum = 1;
for (int i = 2; i <= n; ++i) {
if (i == y) ans = ans * (deg[i]+1) % mod;
else ans = ans * deg[i] % mod;
sum = sum * deg[i] % mod;
}
memset(f, -1, sizeof f); calc(); f[x] = sum * inv[deg[x]] % mod;
ll del = dfs(y);
ans = (ans - del + mod) % mod;
printf("%lld\n", ans);
return 0;
}