拓撲序dp - 落憶楓音(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章