zoukankan      html  css  js  c++  java
  • bzoj4011:[HNOI2015]落忆枫音

    传送门

    首先考虑不加边,那么就是一个有向无环图
    答案的统计就是(sum_{i=2}^{n}in[i])(in[i])就是(i)号点的入度)
    但是考虑加边之后会出现环,那么就会导致重复计数,需要将重复的部分去掉
    重复的原因就是因为环边可能会走到重复的点
    现在考虑新加的边(x->y)
    我们可以发现,只有(y->x)的路径会被重复计算,计算出包含这条路径的树有多少种方案,减掉就好了
    因为在DAG上,拓扑序dp
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=1e5+10,mod=1e9+7;bool vis[maxn];int f[maxn];queue<int>q;
    int cnt,n,m,x,y,ans=1,in[maxn],pre[maxn*2],nxt[maxn*2],h[maxn],ny[maxn];
    void add(int x,int y){pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt;}
    int mi(int a,int b)
    {
    	int ans=1;
    	while(b)
    	{
    		if(b&1)ans=1ll*ans*a%mod;
    		b>>=1,a=1ll*a*a%mod;
    	}
    	return ans;
    }
    void dfs()
    {
    	queue<int>q;
    	f[y]=1ll*ans*ny[y]%mod;
    	for(rg int i=1;i<=n;i++)if(!in[i])q.push(i);
    	while(!q.empty())
    	{
    		int x=q.front();q.pop();
    		for(rg int i=h[x];i;i=nxt[i])
    		{
    			(f[pre[i]]+=(1ll*f[x]*ny[pre[i]])%mod)%=mod;
    			if(!(--in[pre[i]]))q.push(pre[i]);
    		}
    	}
    	ans=(ans-f[x]+mod)%mod;
    }
    int main()
    {
    	read(n),read(m),read(x),read(y),in[y]++;
    	for(rg int i=1,x,y;i<=m;i++)read(x),read(y),in[y]++,add(x,y);
    	for(rg int i=2;i<=n;i++)ans=1ll*ans*in[i]%mod;
    	if(y==1){printf("%d
    ",ans);return 0;}
    	for(rg int i=1;i<=n;i++)ny[i]=mi(in[i],mod-2);in[y]--;
    	dfs();printf("%d
    ",ans);
    }
    
  • 相关阅读:
    QQ群友在线/离线,如何测试?
    QQ好友在线/离线,怎么测试?
    用户体验测试一样很重要
    BUG,带给我的思考
    chrome DevTools
    HTTP、HTTPS
    Knockout双向绑定
    微信小程序
    git fetch 更新远程代码到本地仓库
    Git 同步远程仓库
  • 原文地址:https://www.cnblogs.com/lcxer/p/10567125.html
Copyright © 2011-2022 走看看