#dp#洛谷 3244 [HNOI2015]落忆枫音

题目


分析

每个有入度的点可以选择任意一个父节点组成一棵树,那么原来的答案就是 \(\prod_{i=2}^ndeg[i]\)

现在多了一条边,如果边的终点是1或者它是一个自环那么可以不用管这条边。

然后先把这条边加上再减去不合法的方案,可以发现不合法的方案就是选出任意一个环,它贡献的方案数就是 \(\Large \frac{\prod_{i=2}^ndeg[i]}{\prod_{i\in it}deg[i]}\)

那么设 \(dp[y]\) 表示 \(y\)\(x\) 的环的方案数,\(dp[y]=\frac{1}{deg[y]}\sum{dp[y']}\)

\(dp[x]=\prod_{i=2}^ndeg[i]\),最后不合法的方案就是 \(dp[y]\)


代码

#include <cstdio>
#include <cctype>
using namespace std;
const int N=100011,mod=1000000007;
struct node{int y,next;}e[N<<1];
int dp[N],ieg[N],ans=1,v[N],sum=1,as[N],deg[N],n,m,X,Y;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
int ksm(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans; 
}
void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
void dfs(int x){
	if (v[x]) return;
	v[x]=1;
	for (int i=as[x];i;i=e[i].next)
		dfs(e[i].y),Mo(dp[x],dp[e[i].y]);
	dp[x]=1ll*dp[x]*ieg[x]%mod;
}
int main(){
	n=iut(),m=iut(),X=iut(),Y=iut();
	for (int i=1;i<=m;++i){
		int x=iut(),y=iut();
		e[i]=(node){y,as[x]},as[x]=i;
		++deg[y];
	}
	if (X==Y||Y==1){
		for (int i=2;i<=n;++i) ans=1ll*ans*deg[i]%mod;
		return !printf("%d",ans);
	}
	for (int i=2;i<=n;++i){
		sum=1ll*sum*deg[i]%mod;
		if (i!=Y) ans=1ll*ans*deg[i]%mod;
	}
	ieg[1]=1,Mo(ans,sum);
	for (int i=2;i<=n;++i) ieg[i]=1ll*ieg[i-1]*deg[i]%mod;
	ieg[n]=ksm(ieg[n],mod-2);
	for (int i=n,now=ieg[n];i>1;--i){
		ieg[i]=1ll*ieg[i-1]*now%mod;
		now=1ll*now*deg[i]%mod;
	}
	dp[X]=sum,dfs(Y),Mo(ans,mod-dp[Y]);
	return !printf("%d",ans);
}
posted @ 2022-03-22 20:49  lemondinosaur  阅读(17)  评论(0编辑  收藏  举报