題意:給一張N個點N條有向邊的圖,邊可以逆向。問任意逆向若干條邊使得這張圖無環的方案數(mod 1e9+7)。
思路: 只有兩種情況反邊不能消除環,處理全部不反向和全部反向兩種情況..
對於每一個環,我們都有2^n-2種方案使得這個環不存在,就是2^n減去全部翻轉,和全部不翻轉的方案。
最後再處理不在環上的邊的數量就可以了。
input
3
2 3 1
output
6
#include<cstdio>
#include<cstring>
#include<stack>
#define ll long long
#define mod 1000000007
using namespace std;
int a[220000];
int vis[220000];
int dep[220000];
ll mi[220000];
int dis;
stack<int> st;
struct node
{
int to,nnext;
}edge[220000];
int pre[220000],cnt;
int time;
void init()
{
cnt=0;
time=0;
memset(pre,-1,sizeof(pre));
}
void add_edge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].nnext=pre[u];
pre[u]=cnt++;
}
void dfs(int u)
{
vis[u]=time;
st.push(u);
for(int i=pre[u];i!=-1;i=edge[i].nnext)
{
int v=edge[i].to;
if(!vis[v]) dfs(v);
else if(vis[v]==time)
{
int t=st.top();
dis++;
st.pop();
while(t!=v)
{
t=st.top();
st.pop();
dis++;
}
}
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
init();
mi[0]=1;
for(int i=1;i<220000;i++)
mi[i]=(mi[i-1]*2)%mod;
while(!st.empty()) st.pop();
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
add_edge(i,a[i]);
}
memset(vis,0,sizeof(vis));
memset(dep,0,sizeof(dep));
ll ans=1;
int ydis=n;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
time++;
dis=0;
dfs(i);
if(dis>=2)
ans=ans*(mi[dis]-2+mod)%mod;
ydis-=dis;
}
}
ans=ans*mi[ydis]%mod;
printf("%I64d\n",ans);
}
return 0;
}