1. 程式人生 > >落憶楓音(BZOJ 4011 HNOI2015)

落憶楓音(BZOJ 4011 HNOI2015)

傳送門

Analysis

莫名其妙地被題面虐了一把 很好的一道結論題(?)

朱劉演算法的推論可知,如果除根節點外每個點都選擇一條入邊,由於沒有環,因此一定會形成一個樹形圖 答案就是i=2ndegree[i]∏^n_{i=2}degree[i] 其中degree[i]表示第i個點的入度 但是現在我們加入了一條邊,圖中就可能形成環 我們需要做的就是,依然用上述式子算答案,再減去不合法的環的情況 不合法 環的情況,就是 Syx2jn,jSdegreej\sum_{S是原圖中y\rightarrow x的一條路徑的點集}\prod_{2\leq j\leq n,j\notin S}degree_j

翻譯為人話,就是說:現在強制選擇環,然後其他的點隨便選的不合法方案數 那麼我們的目標就是求出上面那個式子,怎麼求呢? 可以考慮dp,狀態轉移

fi=jifjdegreeif_i=\frac{\sum_{j\rightarrow i}f_j}{degree_i}jj是可以到達ii的點)

Code

#include<bits/stdc++.h>
#define in read()
#define N 100009
#define M 200010
#define P 1000000007
using
namespace std; inline int read(){ char ch;int f=1,res=0; while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1; while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();} return f==1?res:-res; } int n,m,x,y,ans=1; int f[N],inv[M]; int deg[N],__deg[N]; int nxt[M]
,to[M],head[N],ecnt=0; inline void add(int x,int y){nxt[++ecnt]=head[x];head[x]=ecnt;to[ecnt]=y;} inline int mul(int a,int b){return a*1ll*b%P;} inline void topsort(){ queue<int> q; for(int i=1;i<=n;++i) if(!deg[i]) q.push(i); while(!q.empty()){ int u=q.front();q.pop(); f[u]=(f[u]*1ll*inv[__deg[u]])%P; for(int e=head[u];e;e=nxt[e]){ int v=to[e]; f[v]=(f[u]+f[v])%P; --deg[v]; if(!deg[v]) q.push(v); } } } inline void init(){ inv[1]=1; for(int i=2;i<=m+1;++i) inv[i]=(P-P/i)*1ll*inv[P%i]%P; } int main(){ n=in;m=in;x=in;y=in; __deg[y]++; init(); int i,j,k,u,v; for(i=1;i<=m;++i){ u=in;v=in; add(u,v);deg[v]++;__deg[v]++; } for(i=2;i<=n;++i) ans=mul(ans,__deg[i]); if(y==1){ printf("%d",ans); return 0; } f[y]=ans; topsort(); printf("%d",(ans-f[x]+P)%P); return 0; }