这道题怎么可能简单--acwing评分乱搞啊...
首先得知道,把一个环拆成n个自环需要n-1步.然后把一个奇数环拆成两种不同的环x,y的方案数为n,把一个偶数环拆成x==y方案数为n/2,其他都是n.进一步打表可知结论,把一个大小为n的环拆成n个大小为1的自环可行种数为f[n]=n^(n-2).
然后xjb可以乱搞了--好难啊..
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
const int mod=1e9+9;
int a[N];
int vis[N];
int cnt[N];
int f[N];
int sum[N];//打表阶层
vector<int>v[N];
int qp(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void dfs(int pos,int fa,int color)
{
if(vis[pos]) return;
vis[pos]=color;
for(int i=0;i<v[pos].size();i++)
{
if(v[pos][i]==fa) continue;
if(!vis[v[pos][i]])dfs(v[pos][i],pos,color);
}
}
signed main()
{
sum[0]=1;
for(int i=1;i<=N;i++)
{
sum[i]=sum[i-1]*i%mod;
}
int T;
cin>>T;
while(T--)
{
//输入
int n;
memset(cnt,0,sizeof cnt);
memset(vis,0,sizeof vis);
cin>>n;
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
//建边
for(int i=1;i<=n;i++)
{
v[i].push_back(a[i]);
v[a[i]].push_back(i);
}
//进行染色
int k=1;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dfs(i,i,k);
k++;
}
}
k--;
//统计染色状况
for(int i=1;i<=n;i++)
{
cnt[vis[i]]++;
}
//处理f数组
int vv=1;
for(int i=1;i<=k;i++)//f[i]=cnt[i]^(cnt[i]-2).
{
if(cnt[i]<2) f[i]=1;
else f[i]=qp(cnt[i],(cnt[i]-2));
vv=vv*f[i]%mod;
}
//ans就是(n-k)!/((cnt[1]-1)!*(cnt[2]-1)!...(cnt[k]-1)!)*(f[1]*f[2]*...*f[k]).
int ans,lv;
int res=1;
for(int i=1;i<=k;i++)
{
res=res*sum[cnt[i]-1]%mod;
}
lv=qp(res,mod-2);
ans=sum[n-k]*vv%mod*lv%mod;
printf("%lld\n",ans);
}
return 0;
}这个复杂度建议大家照着写,不然不小心就t了hhh
.

京公网安备 11010502036488号