1. 程式人生 > >4011: [HNOI2015]落憶楓音

4011: [HNOI2015]落憶楓音

return pre rod 個數 lin ret typedef https ++

4011: [HNOI2015]落憶楓音

鏈接

分析:

  原來是一個DAG,考慮如何構造樹形圖,顯然可以給每個點找一個父節點,所以樹形圖的個數就是$\prod\limits_u deg[u]$。

  那麽加入一條邊後,我們依然可以按照上面的公式求出一個值T,然後減去不合法的,即存在環的。

  那麽這個環就是X->Y這條邊,和Y->X的一條路徑,X->Y必選了,所以可以考慮求出Y->X的一條路徑,然後這條路徑和X->Y構成的環的答案是$\prod\limits_{u不是這條路徑上的點} deg[u]$

  於是可以dag上dp求了。f[i]表示,確定了路徑Y-i,$\prod\limits_{u不是這條路徑上的點} deg[u]$。

  初始化$f[Y] = T$,然後

代碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long
long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==-)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f; } const int N = 200005, mod = 1e9 + 7; struct Edge{ int to, nxt; } e[N << 1]; int head[N], deg[N], tdeg[N], q[N], inv[N], f[N], En;
int ksm(int a,int b) { int res = 1; while (b) { if (b & 1) res = 1ll * res * a % mod; a = 1ll * a * a % mod; b >>= 1; } return res; } inline void add_edge(int u,int v) { ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En; deg[v] ++; tdeg[v] ++; } int main () { int n = read(), m = read(), X = read(), Y = read(); tdeg[Y] ++; for (int i = 1; i <= m; ++i) { int x = read(), y = read(); add_edge(x, y); } int ans = 1; for (int i = 2; i <= n; ++i) ans = 1ll * ans * tdeg[i] % mod; if (Y == 1) { cout << ans; return 0; } for (int i = 1; i <= m; ++i) inv[i] = ksm(i, mod - 2); int L = 1, R = 0; for (int i = 1; i <= n; ++i) if (deg[i] == 0) q[++R] = i; f[Y] = ans; while (L <= R) { int u = q[L ++]; f[u] = 1ll * f[u] * inv[tdeg[u]] % mod; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; f[v] = (f[v] + f[u]) % mod; if (!(--deg[v])) q[++R] = v; } } cout << (ans - f[X] + mod) % mod; return 0; }

4011: [HNOI2015]落憶楓音