題目大意:給定乙個拓撲圖,然後加一條邊,求加邊後的以1點為根的外向生成樹數目。
題目真(和諧)長。。
首先肯定先考慮在乙個拓撲圖中如何求外向生成樹個數:
對於每乙個點\((2\leq i\leq n)\),很顯然它一定要有一條入邊,這樣在只有1為入度為0的拓撲圖中一定可以形成一棵樹。
那麼第一部分就是:$\prod_^n degree_i \(
然後因為在加一條邊後這個拓撲圖可能變成有環的圖,這樣怎麼辦呢?
這道題很明顯加一條邊的目的之一就是讓你來倒著想的。。。
也就是答案=總方案數(第一部分)-帶環的方案數(第二部分)
既然帶環,並且有邊\)x\to y\(,那麼一定有路徑\)y\to x\(。
確定乙個環以後剩下的點依舊可以隨便連。
那麼設點集\)s\(為\)y\to x\(的一條路徑上的點集。
於是第二部分答案=\)\sum_s\prod degree_j\(
這一部分就可以\)dp\(出來,設\)f_i\(表示從\)y\to i\(的路徑的上面的答案。
那麼有轉移:\)f_i=\frac f_j}$
然後最後減去\(f[x]\)就可以了。
#include#include#include#include#include//#include//#include#includeusing namespace std;
#define ll long long
inline ll read()
const ll inf = 2147483600;
const ll maxn = 300010;
const ll mod = 1000000007;
ll n,m,x,y; ll deg[maxn+1]; ll cnt;
ll node[maxn<<1],next[maxn<<1],root[maxn+1];
inline void insert(ll u,ll v) ll sta[maxn+1],top; ll f[maxn+1];
ll inv[maxn+1]; ll ans=1,in[maxn+1];
vectorvec[maxn+1];
inline ll top_sort() else in[i]=deg[i]; queueque; que.push(1); bool flag=false;
f[y]=ans;
while(!que.empty())
} return f[x];}
int main() for(ll i=2;i<=n;i++) ans=ans*(deg[i]+(i==y))%mod;
if(y==1)
printf("%lld\n",(ans-top_sort()+mod)%mod);
return 0;
}
BZOJ 4011 HNOI2015 落憶楓音
題意 給乙個有向無環圖,然後叫一條邊,問以1為根的生成樹數量。題面好長啊,出題人真能編故事 先考慮不加那條邊,則麼ans d 2 d 3 d 4 d n d為入度 因為在乙個dag中,只要除根以外的點每個點選一條入邊,就能獲得一棵生成樹。現在考慮加了這條邊,如果再這麼算,就有可能出現環的情況,所以我...
BZOJ4011 HNOI2015 落憶楓音
用脈絡樹總數減去不合法的情況 即樹上有環的情況 拓撲序dp,注意特判連的邊指向1的情況 學到了新姿勢 線性求逆元 原理 假設現在要求a的逆元,x mod a,y mod a ax y 0 ax y a 1 x y 1 ax y 0 ax y a 1 x y 1 code include includ...
BZOJ4011 HNOI2015 落憶楓音
不妨假設楓葉上有 n個穴位,穴位的編號為 1 n。有若干條有向的脈絡連線著這些穴位。穴位和脈絡組成乙個有向無環圖 稱之為脈絡圖 例如圖 1 穴位的編號使得穴位 1 沒有從其他穴位連向它的脈絡,即穴位 1 只有連出去的脈絡 由上面的故事可知,這個有向無環圖存在乙個樹形子圖,它是以穴位 1為根的包含全部...