luogu3244 bzoj4011 HNOI2015 落忆枫音
這道題目題面真長,廢話一堆。
另外:這大概是我第一道獨立做出來的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; }?
轉載于:https://www.cnblogs.com/1-1-1-1/p/8596753.html
總結
以上是生活随笔為你收集整理的luogu3244 bzoj4011 HNOI2015 落忆枫音的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 银行卡冻结了怎么把钱取出来
- 下一篇: django 在保存数据前进行数据校验