[BZOJ4011][树形DP]HNOI2015:落忆枫音

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/88981753

BZOJ4011

题意:给个DAG和一条额外的边,求以1为根的有向生成树个数

分析:如果没有额外的边,那么考虑乘法原理得到答案就是 i = 2 n i n [ i ] \prod_{i=2}^n{in[i]}
加上额外的边后,可能生成环(如果没有就一样的)
多出来的选择就是环上的点都选了环上的父亲
那么我们设 f [ x ] f[x] x x s s (给出的额外边)上产生的贡献,转移就是
f [ x ] = f [ t o [ x ] ] / i n [ x ] f[x]=\sum{f[to[x]]/in[x]}

Code:

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1e5+5;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0;
int in[N],sum=1;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
inline int ksm(int a,int b){int res=1; for(;b;b>>=1){if(b&1) res=(ll)res*a%mod;a=(ll)a*a%mod;} return res;}
int pt[N],s,t,f[N];
void dfs(int v){
	if(pt[v]) return;
	pt[v]=1;
	if(v==t) {f[v]=(ll)sum*ksm(in[v],mod-2)%mod;return;}
	for(int i=head[v];i;i=nxt[i])
		dfs(vis[i]),f[v]=(f[v]+f[vis[i]])%mod;
	f[v]=(ll)f[v]*ksm(in[v],mod-2)%mod;
}
int ans=1;
int main(){
	int n=read(),m=read();s=read(),t=read();
	for(int x,y,i=1;i<=m;i++) x=read(),y=read(),add(y,x),++in[y];
	in[1]++;
	for(int i=1;i<=n;++i) {
		if(i==t) ans=(ll)(in[i]+1)*ans%mod;
		else ans=(ll)in[i]*ans%mod;
		sum=(ll)in[i]*sum%mod;
	}
	dfs(s);
	ans=(ans+mod-f[s])%mod;
	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/88981753