题目
给定一个长度为n(n<=1e6)的序列,第i个数ai(1<=ai<=n),
操作:你可以将当前i位置的数和a[i]位置的数交换
交换可以操作任意次,求所有本质不同的数组的数量,答案对1e9+7取模
思路来源
力扣群 潼神
心得
感觉已经说的很详尽了,甚至没什么需要补充的地方...
不难发现,自环的情况和>=2的环的情况是统一的,所以dfs找环即可
组合题更多的是一种无从下手的感觉,需要多培养手玩性质的能力
比如,发现a->b->c到a->c,b->b这个性质,然后再着手计数
代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<ll,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef unsigned ui;
//typedef __uint128_t L;
typedef unsigned long long L;
typedef unsigned long long ull;
const int N=1e6+10,mod=1e9+7;
int n,v,to[N],deg[N];
vector<int>e[N];
int stk[N],c,ans=1;
bool vis[N],in[N];
void dfs(int u){
if(!u)return;
stk[++c]=u;
in[u]=1;
vis[u]=1;
int v=to[u];
if(in[v]){//环的情况 统一了自环的情况
int res=1,sub=0;
while(c){
int w=stk[c--];in[w]=0;
res=1ll*res*(deg[w]+1)%mod;
sub=(sub+deg[w])%mod;
if(w==v)break;
}
res=(res+mod-sub)%mod;
ans=1ll*ans*res%mod;
}
if(!vis[v])dfs(v);
}
int main(){
sci(n);
rep(i,1,n){
sci(v);
to[i]=v;
deg[v]++;
}
rep(i,1,n){
if(!vis[i]){
dfs(i);
}
while(c){
int w=stk[c--];in[w]=0;
ans=1ll*ans*(deg[w]+1)%mod;
}
}
printf("%d\n",ans);
return 0;
}