1. 程式人生 > >luogu3244 bzoj4011 HNOI2015 落憶楓音

luogu3244 bzoj4011 HNOI2015 落憶楓音

做出 () 了吧 push AR 選擇 為什麽 成了 之前

這道題目題面真長,廢話一堆。

另外:這大概是我第一道獨立做出來的HNOI2011年以後的題目了吧。像我水平這麽差的都能做出來,dalao您不妨試一下自己想想?

題目大意:給一個DAG,其中1號點沒有入度,現在新加入一條不重復的邊,使得它可能有環。求它的生成子圖個數,使得子圖正好包含N-1條邊且1號點與其它的所有點連通。

題目分析:

我們首先要發現這是一個樹的結構!有向的樹。

分析樹的特點,樹的父親只有一個,我們不妨從這裏入手。

在這一個生成子圖中,誰是誰的父親?

我們知道1號點一定是root,這是為什麽呢?

原因在於一號點沒有入度,我們就認為了它是root。

那麽假設有一條x->y的路徑,那麽x就是y的父親,這樣的定義是合理的。

考慮不加邊之前的情況,圖是一個DAG,我們求它的生成樹(姑且這麽叫吧)。

根據我們上面的分析,我們猜想:除一號點外所有點的入度乘積為該圖的生成樹數量。

證明如下:

首先我們考慮這個是怎麽來的。每個點選擇一個父親,則根據乘法原理得到上面的猜想。

那麽我們的命題是:每個點選一個父親,則這個方案必定合法。

我們一共對N-1個點選了到fa的邊,每次選擇都合並了兩個點,共合並了N-1次,因此共N個點被合並,又由於不存在環的情況,所以這樣的方案是合法的。

考慮多了一條邊的情況。那麽我們由於已經求得了所有不包含這條邊的情況,我們只需要分析多了這條邊的情況。

假設這是一條從x到y的邊。當這條邊必選的時候,y點必定不被考慮。因為它的父親已經確定。

那麽我們對剩下的點重新做一遍乘法,得到了ans2。

考慮答案多了什麽。

當選出的邊與當前邊成環的時候,這個並不是一個生成樹,我們沒辦法解決了嗎?當然不是。

我們不妨單獨拿出一個環考慮。當形成了這個環的時候,對答案的影響是多少。實際上這不難統計,把剩下的點的入度全部乘起來就是答案。嘿嘿,這不就是總和除以現在的點數嗎。

那麽我們考慮求y到x的路徑的點的入度的逆,DP一發輕松解決。然後乘法分配率證明正確性。

後記:這題我先寫了個錯的然後發現我想錯了,答案小了,調了調變大了,然後又調,結果搜索出了正解233。

代碼:

#include<bits/stdc++.h>
using
namespace std; typedef long long ll; const int maxn = 102000; const int mod = 1000000007; int n,m,x,y; ll ans,ans2; int in[maxn],arr[maxn]; ll dist[maxn],inv[maxn]; vector <int> g[maxn]; vector <int> ng[maxn]; ll fast_pow(int now,int p){ if(p == 1) return now; if(p == 0) return 1; ll z = fast_pow(now,p/2); z*=z; z %= mod; if(p & 1){z*=now;z%=mod;} return z; } void read(){ scanf("%d%d%d%d",&n,&m,&x,&y); for(int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); g[a].push_back(b);in[b]++; ng[b].push_back(a); } for(int i=2;i<=n;i++) inv[i] = fast_pow(in[i],mod-2); } void dfs(int now){ if(arr[now]) return; arr[now] = 1; for(int i=0;i<ng[now].size();i++){ dfs(ng[now][i]); dist[now] += (dist[ng[now][i]]*inv[now])%mod; dist[now] %= mod; } } void work(){ ans = ans2 = 1; for(int i=2;i<=n;i++) ans = (ans*in[i]) % mod; if(x == y){printf("%lld\n",ans);return;} if(y == 1){printf("%lld\n",ans);return;} for(int i=2;i<=n;i++) if(i != y) ans2 = (ans2*in[i]) % mod; in[y]++;inv[y] = fast_pow(in[y],mod-2);dist[y] = inv[y];arr[y] = 1;dfs(x); ans += ans2; ans %= mod; ans -= (ans*dist[x])%mod; ans += mod; ans %= mod; printf("%lld\n",ans); } int main(){ read(); work(); return 0; }

luogu3244 bzoj4011 HNOI2015 落憶楓音