题意:给定一个
设把
求有多少种操作方法可以只用
因为结果可能很大,你只需要输出结果对
例如排列
方法一:先交换数字
方法二:先交换数字
方法三:先交换数字
对于每个排列
最后目标排列为
引理:
把一个长度为
设
在操作中,我们可以把该环拆成长度为
另外,二者各自变为自环的方法数为
可得:
如果最初的排列构成的图,有长度为
于是bfs找环解决,事实上,我们可以发现,
code:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int mod=1e9+9;
int t,n,tot;
int head[401010],cnt;
long long fac[101010],inv[101010],ans;
int vise[401010],visv[101010],len[101010];
struct node
{
int next;
int to;
}e[401010];
void add(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
void dfs(int u,int p,int r)
{
if(!visv[u])
{
len[p]++;
visv[u]=1;
}
for(int i=head[u];i;i=e[i].next)
{
if(vise[i]==r)
continue;
vise[i]=vise[i^1]=r;
dfs(e[i].to,p,r);
}
}
long long power(long long a,long long b,long long p)
{
if(b<=0)
return 1;
long long ans=1%p;
for(;b;b>>=1)
{
if(b&1)
ans=ans*a%p;
a=a*a%p;
}
return ans%p;
}
int main()
{
fac[0]=inv[0]=1;
for(int i=1;i<=100000;i++)
{
fac[i]=(fac[i-1]%mod*i%mod)%mod;
inv[i]=power(fac[i],mod-2,mod)%mod;
}
scanf("%d",&t);
for(int _=1;_<=t;_++)
{
memset(e,0,sizeof(e));
memset(vise,0,sizeof(vise));
memset(visv,0,sizeof(visv));
memset(len,0,sizeof(len));
memset(head,0,sizeof(head));
ans=0;
cnt=1;
tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
add(i,x);
add(x,i);
}
for(int i=1;i<=n;i++)
if(!visv[i])
dfs(i,++tot,_);
ans=fac[n-tot];
for(int i=1;i<=tot;i++)
ans=(ans%mod*power(len[i],len[i]-2,mod)%mod*inv[len[i]-1]%mod)%mod;
printf("%lld\n",ans);
}
return 0;
}