http://codeforces.com/contest/711/problem/D
给一个图,n点n边, 问有多少个边集 翻转其方向 后使得整个图不存在任一个有向环。
那么直接dfs找出一个联通分量,然后根据深度判一下环的长度为huan,该联通分量点数为tol
那么答案就是 乘上 (2^huan)-2 + 2^tol , 环的情况减二是因为 去掉两个怎么翻都是环的情况(正环和反环)
注意预处理一下2的幂,取模,然后就没了。。。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=0.000001;
typedef long long ll;
const int N=2*100000+50;
int vis[N];
vector<int > mp[N];
int tol,huan,tmp;
ll mod=1e9+7;
int dep[N];
long long powe_m(long long a,long long b )
{
long long ans=1;
long long tmp=a;
while(b!=0)
{
if (b&1)
ans=ans*tmp%mod;
tmp=tmp*tmp%mod;
b=b>>1;
}
return ans;
}
ll two[N];
void dfs(int x,int h)
{
tol++;
vis[x]=1;
dep[x]=h;
for (int i=0;i<mp[x].size();i++)
{
int v=mp[x][i];
if (dep[v])
{
huan=dep[x]-dep[v]+1;
break;
}
if (vis[v]) break;
dfs(v,h+1);
}
dep[x]=0;
}
int main()
{
ll n,m,k;
cin>>n;
two[0]=1;
for (int i=1;i<=n;i++)
two[i]=two[i-1]*2%mod;
int x;
for (int i=1; i<=n; i++)
{
scanf("%d",&x);
mp[i].push_back(x);
}
ll ans=1;
for (int i=1; i<=n; i++)
{
if (vis[i] )continue;
tol=0;
huan=0;
dfs(i ,1);
if(huan )
ans= ans* ((two[huan]-2+mod)%mod)%mod*two[tol-huan]%mod;
else
ans= ans *two[tol]%mod;
}
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}