【CF711D】Directed Roads

题目大意:给定一个 N 个点,N 条边的无向图,现给每条边定向,求有多少种定向方式使得定向后的有向图中无环。

题解:显然,这是一个外向树森林,定向后存在环的情况只能发生在基环树中环的位置,环分成顺时针和逆时针两种情况,其他边方向随意。因此,记外向树森林中环的大小为 \(w[i]\),则答案为$$2^{n-\sum w[i]}*\prod (2^{w[i]}-2)$$

代码如下

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
	ll x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}

vector<P> G[maxn];int tot=1;
int n,m,dep[maxn],vis[maxn];
ll ans=1,p[maxn];

void read_and_parse(){
	n=m=read(),p[0]=1;
	for(int i=1;i<=n;i++)p[i]=p[i-1]*2%mod;
	for(int i=1,to;i<=n;i++)to=read(),G[i].pb(mp(to,++tot)),G[to].pb(mp(i,++tot));
}

void dfs(int u,int fe){
	vis[u]=1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].first,e=G[u][i].second;if(fe==(e^1))continue;
		if(!vis[v])dep[v]=dep[u]+1,dfs(v,e);
		else if(vis[v]==1)m-=dep[u]-dep[v]+1,ans=ans*(p[dep[u]-dep[v]+1]-2)%mod;
	}
	vis[u]=2;
}

void solve(){
	for(int i=1;i<=n;i++)if(!vis[i])dfs(i,0);
	ans=ans*p[m]%mod;
	printf("%lld\n",ans);
}

int main(){
	read_and_parse();
	solve();
	return 0;
}

posted @ 2019-02-18 17:49  shellpicker  阅读(182)  评论(0编辑  收藏  举报