题目链接:https://www.acwing.com/problem/content/214/
给出一个排列打乱之后的顺序,要求将其还原成升序全排列的方法数,通过计算,将一个长度为n的环变成自环需要用n-1步,将一个长度为n的环变成自环可能的步数有n^(n-2)种,假设这个给出的全排列中环的数量是k,那么一共需要n-k步。由于每次步数的选择中,每一类的是没有顺序的,所以需要利用多重集的公式进行去重。
代码:
#include<iostream> #include<cstdio> #include<string.h> using namespace std; const int maxn = 100010; const int mod = 1000000009; typedef long long ll; ll jc[maxn]; int n; int a[maxn],p[maxn]; bool vis[maxn]; ll power(ll a,ll b){ ll ans=1; b%=mod; while(b){ if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } int main(){ jc[0]=1; for(int i=1;i<=maxn-1;i++)jc[i]=(jc[i-1]*i)%mod; int T; cin>>T; while(T--){ cin>>n; int cnt=0; ll ans=1; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)p[i]=a[i]; for(int i=1;i<=n;i++){ if(vis[i])continue; int len=1; vis[i]=1; for(int j=p[i];j!=i;j=p[j])vis[j]=1,len++; cnt++; ans=(ans*(len==1?1:power(len,len-2)))%mod; ans=(ans*power(jc[len-1],mod-2))%mod;//求解逆元 } ans=(ans*jc[n-cnt])%mod; cout<<ans<<endl; } return 0; }